forやめろ -- ll diver 2014 lt枠
DESCRIPTION
LL Diver 2014TRANSCRIPT
forやめろ
esehara shigeo
お前誰だ
esehara shigeo趣味:言語いじりFizzBuzzの研究
数論・数理論理学←New!!PythonistaClojuren
最初に結論を
時代はStaticおじさん
からforおじさんへ
では始めます
FizzBuzzではない新しい採用試験のご案内
1から100の整数を出力してください
ただし5つの
異なる方法を用いて
1から100の整数を出力してください
ただし5つの異なる方法を用いて
そもそも「繰り返し」とは何か問題
あるブロックを
ある条件の間
何度も実行すること
ちょっとまて繰り返しって
そんな自明なことだっけ?
「繰り返し」における再帰と反復
● ある種の問題の解は再帰を使うと容易に定式化できる
● ある種の問題に対する反復解は、再帰解ほど自明ではない
● 一般に、反復解は再帰解より効率的である(関数呼び出しのオーバヘッドのため)。
既に2パターンあるじゃねえか!!!
だからこそ、繰り返しの知見が
必要になる
最も有名な反復の方法
GOTO
GOTOが使える言語といえば
● C言語● CSH● BASIC● FORTRAN● GO
NO!そんなの
メインじゃない!
PHP
PHPにおけるGOTO
<?php$a = 0;
incr_loop:
$a++;echo $a . "\n";if ($a < 100) goto incr_loop;
GOTOでわかること
● GOTOを使った繰り返しとは、「ある条件のときに、あるラベルがある場所に戻る」ことである、と説明ができる
GOTOにおける反復のポイント
● ラベルの前で変数を初期化● 条件を満たしているなら任意のラベルに移動
● 変数に新しい値を代入する
****における反復のポイント
● ブロックの前で変数を初期化● 条件を満たしているならブロックの最初に戻る
● 変数に新しい値を代入する
while
PythonにおけるWhile
a = 0
while a < 100: a += 1 print(a)
whileなんて使わないでしょ?
いらないよね(^ー^)
GO
Goにおけるwhileっぽいアレpackage main
import "fmt"
func use_for(b int) {a := 0for ; a < b; {
a += 1fmt.Println(a)
}}
func main() {use_for(100)
}
ここで皆さんにお知らせです
テスト書けクソども
ついでなのでテストpackage main
func ExampleUseFor() {
use_for(5) // Output:
// 1// 2// 3// 4// 5
}
whileからわかること
● 「あるラベルからGOTOで飛ぶ範囲」を「ブロック」としてまとめることができれば、「ブロックの繰り返し」として説明できる
whileにおける反復のポイント
● 変数を初期化● 条件を満たしているならwhileのブロックの最初に戻る
● 変数に新しい値を代入する
あれ?ブロックを関数でまとめちゃえば
いいんじゃないの?
再帰
**における繰り返しのポイント
● 初期値を関数の引数に● 条件を満たしていないなら自身をもう一度呼ぶ
● 自身を呼ぶときに新しい値を渡す
Schemeにおける再帰
(define (ref-loop i j) (if (<= i j)
(begin(print i) (ref-loop (+ i 1) j))))
(ref-loop 1 100)
再帰からわかること
● 「ブロック」としてまとめることができる、ということはその「ブロック」自体を関数にすることが可能である
〔再掲〕 関数における繰り返しのポイント
● 初期値を関数の引数に● 条件を満たしていないなら自身をもう一度呼ぶ
● 自身を呼ぶときに新しい値を渡す
理論的には
● プログラミングコード、それ自体も実は一つの大きなブロックとしてとらえることができる(例:テンプレートエンジン)
**における再帰のポイント
● 初期値をオプション引数に● 条件を満たしていないなら自身(スクリプ
ト)をもう一度実行する● 自身を実行するときに新しい引数を渡
す
Bash
話は戻ります
この時期の学生
「プログラムにおけるfor文が難しいよぉ」
俺も正直難しいと思っている
forがやっていることの面倒くささ
● 変数を初期化● 繰り返し
○ ブロックの最初に戻る○ 条件を満たした場合はブロックを実行
● 変数に新しい値を代入する
JavaScriptによる例
for (var i = 0; i <= 100; i++) { console.log(i);}
Pythonでwhileでforを書き直すと
a = 0
while True: if a >= 100: break a += 1 print(a)
三つのことを同時に
考慮しないとダメ
forがやっていることの面倒くささ
● 変数を初期値とは?● 条件を満たす、とは?● 変数に新しい値を代入する、とは?
プログラミングできない駄目な妹(妄想上)はこういうわけですよ
ふええ……難しいよお><
だったらこれでいいよねお兄ちゃん……
***による繰り返し
● 任意の配列Xを用意する● Xの要素yに対して、任意のブロックおよ
び関数を適用する● これを全ての要素に適用する過程を使
えば、繰り返しとなる
each
Rubyによる例
(1..100).each do |v| puts vend
eachからわかること
● ブロックを関数などの一つの実行単位としてまとめることができるなら、それを「ある集合」の「要素」に適用させていく過程、という書き換えることができる
博士の知っ得豆知識
「この配列の要素を取り出すインターフェイスをイテレーターっぽく共通化すれば、任意のオブジェクトを配列のようにあつかえるのじゃ」
「お前誰だよ」
ふええ……配列に対して二乗した結果が欲しいですぅ……
配列操作に対して安易にfor使うな
● 超べんりforブロックに成長(一ブロック1000行!)
● 並列化したいとき、切り分けが発生する● テストが配列に対するものになる
map
Pythonによる例
from __future__ import print_function
map(print, range(101))
mapからわかること
● それを「ある集合」の「要素」に適用させていく過程を行うことで、「要素それぞれに対して関数を適用した結果」となるように書いた方が、可読性があがる
そんなこと考えてるの頭でっかちな
ウェッブケーでしょ(笑)
Java8Stream API
最後に結論を
Q.for使ってもいい時は
ありますか?
私見・forを使わないほうがいいとき
● 配列を加工した結果として、新しい配列が必要な場合
● ほかの表現のほうがより適している場合(whileとかeachとかあるでしょ)
私見・forを使うほうがいいとき
● forでパフォーマンスを改善できる場合
● 言語的な仕様によって、上記アプローチが使えないとき
forを使っていいとき・巨大数を作る
最後に改めて
人間の考えを機械に合わせる
のではなく機械のほうが
人間にあわせていく
過去の慣習にあわせるのではなく
未来の進歩へ変化していく
時代はStaticおじさん
からforおじさんへ
ありがとうございました