メイキング オブ 関数型プログラミングマンガ -...
TRANSCRIPT
メイキングオブ
関数型プログラミングマンガ
esehara shigeo
謝罪
サンプルコード全く書けませんでした
圧倒的土下座
気をとりなおして
お前誰だ
esehara shigeo (31)twitter: @esehara
Logbar Inc.Clojuren
最近の趣味: OCaml
現在の画力
『マンガでわか『マンガでわかる!関数型プログラミング』やめてほしいとしか思ってない『マンガでわかる!関数型プログラミング』やめてほしいとしか思ってないマンガでわかる!関数型プログラミング』やめてほしいとしか思ってない『マンガでわかる!関数型プログラミング』やめてほしいとしか思ってない『マンガでわかる!関数型プログラミング』やめてほしいとしか思ってない『マンガでわかる!関数型プログラミング』やめてほしいとしか思ってない『マンガでわかる!関数型プログラミング』やめてほしいとしか思ってないる!関数『マンガでわかる!関数型プログラミング』やめてほしいとしか思ってない型プログラミング』やめてほしいとしか思ってない
一応、こういう地道な練習はしているんですよ……
圧倒的現実
進捗
現段階でボツネーム4回目
人間がゾンビ化した世界
ネオナゴヤで「食料」を奪取する為の関数型プログラミング…
締め切りまで
あと11日
無事、彼は原稿を届けることが出来るのだろうか
続報を待て
結論:
マンガを書くのは難しい
宣伝終了
最高のIoTデバイス買ってください!!
宣伝終了
ところで何処が「関数型
プログラミング」なんですか
本題
なぜ関数型プログラミングを
「説明」することが難しいのか
esehara shigeo
問題
そもそも「関数型プログラミング」と定義される場合の「関数型」の特徴とは?
関数型プログラミングの特徴は「関数を第一級の対象(first class-object)である」、つまり関数を引数にしたり、関数を結果の値とするようなもの。(by 『関数型プログラミング』R.ロバート/P.ワドラーより)
現状、PythonやJavaScriptは「関数を第一級の対象」にできるといえるわけだから、ちょっとこれでは説明が足りない
関数型プログラミングは、コマン
ドの実行を強調するプログラミン
グスタイルではなく、式の評価を
強調します。これらの言語での式
(expression)は、基本的な値を
結合するための関数を用いて形
成されています。関数型言語ファ
ンクショナルなスタイルでプログ
ラミングを推奨し、サポートする
言語です。
Functional programming is a style of programming that emphasizes the evaluation of expressions, rather than execution of commands. The expressions in these language are formed by using functions to combine basic values. A functional language is a language that supports and encourages programming in a functional style.
代入を使わないうちは, 同じ引数での同じ手続きの二回の評価は同じ結果を生じ,手続きは数学的関数を計算すると見ることが出来た. 本書の初めの二章でやったように, 代入を使わないプログラミングは, 従って 関数型プログラミング(functional programming)という.
(by SICP)
「副作用をできるだけ(あるいは全く)用いず、式や関数で計算を表すプログラミングスタイルのことです。」
(by Eijiro Sumii)
筆者の関数プログラミングの定義,すなわちこの特集での定義
は,「永続データプログラミング」です。永続データとは,破壊でき
ないデータ,つまり再代入できないデータのことです。そして,永
続データを駆使して問題を解くのが永続データプログラミングで
す。
また関数型言語とは,永続データプログラミングを奨励し支援し
ている言語のことです。関数型言語では,再代入の機能がない
か,再代入の使用は限定されています。筆者の定義はかなり厳
しいほうだと言えます。(by 山本和彦)
死ぬほど定義出てくる
時点でムズい!!
強引なまとめ
● 関数を第一級オブジェクト(=値と同一)のものとして取り扱う(これはそうではない言語もあるので怪しい?)
● 副作用をできるだけ使わず、式や関数で表現する
● イミュータブルな(不変のデータ構造)を重要視する
蛇足
最近の本(『実践関数プログラミング』)だと、いわゆる「Lisp」(正確にはCommon Lisp、Scheme)という理由だけで関数型言語の仲間には入れない感じ(Lispは”Lisp”というパラタイム)Common Lispはバリバリ、データ構造を変更しまくる。ただ、Clojureは不変のデータ構造を意識させるために仲間にされることはある(いちおう、Racket langという処理系も、明示的にデータをImmutableにすることは可能)
歴史
「オブジェクト指向」vs
「関数型プログラミング」
「オブジェクト指向」vs
「関数型プログラミング」
前段階としての構造化
プログラミング
「順次、分岐、反復」の三種の神器
top-down program development
+stepwise refinement
批判
構造化プログラミングは制御の流れしか捉えられておらん
そもそも計算のパターンと
状態の変化そのものを対応するのは
難しいやろが
代入
そもそも変化とは何か
(哲学)
参照透明性を一旦捨てると, 計算オブジェクトが「同じ」であるとは何を意味するかの概念を形式的に捕らえるのは難しくなる. 実はわれわれのプログラムがモデル化している実世界の「同じ」の意味もあまりはっきりしない. 一般に二つの見かけ上同じなオブジェクトが本当に「同じもの」であるかは, 一つのオブジェクトを変えてみて, もう一つのオブジェクトが同じように変っているかを見て決める. しかし「同じ」オブジェクトを二度観測し, オブジェクトのある性質が一回目と二回目の観測で違っているということ以外に, あるオブジェクトが「変った」ことがどうして分るだろうか. つまり何か先験的な 「同一」という概念なしに「変化」を決めることは出来ず, 変化の効果を観測することなしに同一性を決めることは出来ない.(SICPより)
手続き型プログラムを学ぶ際の障壁の一つが代入(assignment)の概念であることは随所で指摘されている。これは計算過程と計算状態という考え方が初心者にとっては新奇なものでなじめないということにも理由があろう。
多くのプログラミング学習者が理解に苦しむ問題を調査した所、以
下のような結果が得られた。
●代入とシーケンス実行
●再帰と繰り返し実行
●並列実行
再帰やループはたしかに難しい。並列実行はとても難しいが、多く
の挫折者はそこまで到達しない。しかし、代入とシーケンス実行とい
う、プログラミングの最も基本的である概念の理解に苦しむとはどう
いうことか。 (60%の人間はプログラミングの素質がない - 本の虫)
破壊的代入は強すぎる
強すぎる=
ハイリスクハイリターン
逆に関数型プログラミングの
理解のしにくさは何処にある
調査
大体こんな感じ?● インターネットがまだ無い時代に図書館で読み漁った本で、
まず、関数っていう物の意味が分からなかったんですよね。
● 「実行順序の無いプログラム」というのがよく分かりません。
「SQLもループ処理の一部を書いているだけだ」と理解して
いる私にとっては、ループを使わずにプログラムを書くという
ことが既に分かりません。
● 競技プログラミングの問題をたまに解いたりする程度です
が、最初は変数が書き換えられないということに大きな衝撃
を受けました。
大体こんな感じ?● インターネットがまだ無い時代に図書館で読み漁った本で、
まず、関数っていう物の意味が分からなかったんですよね。
● 「実行順序の無いプログラム」というのがよく分かりません。
「SQLもループ処理の一部を書いているだけだ」と理解して
いる私にとっては、ループを使わずにプログラムを書くという
ことが既に分かりません。
● 競技プログラミングの問題をたまに解いたりする程度です
が、最初は変数が書き換えられないということに大きな衝撃
を受けました。
多くのプログラミング学習者が理解に苦しむ問題を調査した所、以
下のような結果が得られた。
●代入とシーケンス実行
●再帰と繰り返し実行
●並列実行
再帰やループはたしかに難しい。並列実行はとても難しいが、多く
の挫折者はそこまで到達しない。しかし、代入とシーケンス実行とい
う、プログラミングの最も基本的である概念の理解に苦しむとはどう
いうことか。 (60%の人間はプログラミングの素質がない - 本の虫)
再帰関数副作用
関数
関数型プログラミングにおける関数とは「与えられた入力の値のみから出力となる値をただ1つ決める規則」という数学的な意味での関数です(『実践関数プログラミング入
門』)
ちょっとまてや
プログラミングの用語として、関数のような「(類似の)一連の処理をまとめた単位」をサブルーチン(subroutine)、もしくは手続き(procedure)とも呼ぶ.これらの概念の境界は必ずしも明確ではないが、手続きは処理だけを行い返り値を持たないもの、関数は返り値があるもの、と区別される傾向がある。
問題は値を得ること
テストが素早く済めば,もっと頻繁にテストができる. Lispでは(他のどのプログラミング言語でもそうだが),ソフトウェア開発はコード書きとテストのサイクルから成る. しかしLispではサイクルがとても短い: 関数1個毎,いや関数の部分毎でもいい. あらゆる部分を書くにつれてテストすれば, エラーが起きたときにどこを見ればいいか分かるだろう: 最後に書いた部分だ.単純に聞こえるが,この原則はボトムアップ・プログラミングを堅固なものにしている要因の 大きな割合を占めている.それは更なる自信をもたらし,Lispプログラマは(少なくともある一時) 古い「計画−実装」スタイルのソフトウェア開発からフリーになれるのだ.(『On Lisp』より)
問題は、このようなボトムアップなコーディングにあまり慣れない
部分を寄せ合わせるという発想
再帰
再帰は数学から生まれた有用な技法である。再帰コードは一般に、反復コードよりも短くて書きやすい。
ちょっとまてや
whileにおける反復のポイント
● 変数を初期化● 条件を満たしているならwhileのブロックの最初に戻る
● 変数に新しい値を代入する
PythonにおけるWhile
a = 0
while a < 100: a += 1 print(a)
あれ?ブロックを関数でまとめちゃえば
いいんじゃないの?
再帰からわかること
● 「ブロック」としてまとめることができる、ということはその「ブロック」自体を関数にすることが可能である
Schemeにおける再帰
(define (ref-loop i j) (if (<= i j)
(begin(print i) (ref-loop (+ i 1)j))))
(ref-loop 1 100)
ソフトウェア開発はコード書きとテストのサイクルから成る.しかしLispではサイクルがとても短い: 関数1個毎,いや関数の部分毎でもいい.
一気にロジックを書き上げようとすると死ぬ
部分を寄せ合わせるときに
型チェックがあると便利(テストのサイクルに
組み込まれる)
注意
再帰は強すぎる
だいたいの再帰を利用したループは
mapなどの高階関数で表現することが可能
結論
なぜ関数型プログラミングを
「説明」することが難しいのか
トップレベルで書き下すことからボトムアップで
繋ぎ合わせていくという発想の転換が難しい
ブロックで処理を数十行書くのではなく
細かく関数を切り分けて作り上げて繋げるというのが難しい
逆に代入による計算過程と計算状態という考え方に慣れすぎているために難しい。
泥団子のように関数を小さく始めてみよう