Slide 1

Slide 1 text

低レベル勉強会 前半 関数型プログラミングの考え方について 後半 Scheme入門 2021-09-14 追記版

Slide 2

Slide 2 text

自己紹介 sou7です。会津大学の学部1年生です これまでに触れた関数型言語(と、それを含むマルチパラダイム言語)は Elm Scheme Scala Rust(ほんのちょっと) です。 そこまで関数型バリバリな人ではないので、理解が曖昧な箇所も多いですが、できる 限りやっていければと思います ちなみにSchemeも一部理解した程度です・・

Slide 3

Slide 3 text

各種SNSアカウントなど Twitter GitHub Discord @sou7_ _ _ @soukouki sou7#0094

Slide 4

Slide 4 text

大まかな流れ 関数型言語の考え方について ファーストクラスクロージャや、参照透明性などの考え方について触れます Scheme入門 SchemeインタプリタのGaucheを用いて、実際にSchemeのコードを書いて、Lispの構 文にある程度慣れるところまで行きたいです

Slide 5

Slide 5 text

関数型言語の考え方について

Slide 6

Slide 6 text

他のプログラミングパラダイムとの比較 手続き型プログラミング オブジェクト指向プログラミング マルチパラダイム

Slide 7

Slide 7 text

手続き型プログラミング 状態を書き換えて計算を進める 変数への代入 ループ 手続き呼び出し 例:C, brainfuckなど

Slide 8

Slide 8 text

オブジェクト指向プログラミング 手続きを抽象化する手法の一つ データと手続きを一塊として扱う 例:C++, Javaなど

Slide 9

Slide 9 text

マルチパラダイム 関数型とオブジェクト指向の融合を目指す 例:Scala オブジェクト指向言語への関数型の導入 例:Java, Pythonなど マルチパラダイム言語が増えていて、パラダイムの違いが曖昧になってきている

Slide 10

Slide 10 text

関数型プログラミングの特徴 (数学的な)関数を評価することで計算を進める クロージャを値として扱える(ファーストクラスクロージャ) 関数を値のように扱える 関数ポインタとの違い クロージャの式の中にクロージャの式を書ける (C言語では、関数の中で関数を定義することは出来ない) クロージャを生成する際に、外側の変数の値を使用できる 参照透明である 同じ引数で関数を呼び出すと、必ず同じ結果が帰ってくる 関数が状態を持たないことを保証できる 並列処理や自動テストに都合が良い 例:Lisp, Haskell, Elmなど

Slide 11

Slide 11 text

参照透過でない例 呼び出す度に状態が変化する 状態の変化(副作用という)がある int count() { static int cur = 0; cur++; return cur; }

Slide 12

Slide 12 text

ループについて ループはない ループは副作用を前提としているため int sum = 0; for(int i=0; i<100; i++){ sum += i; }

Slide 13

Slide 13 text

それでも、副作用が必要なときもある 入出力など、どうにかして副作用を扱う必要があります なので、関数型言語は様々な手法でそれを乗り越えようとしています 諦めて、参照透明でない書き方ができるようにする Scheme, Common Lisp, ML モナド 例:Haskell 一意型 1度しか参照できない型を用意して、過去の時点のインスタンスに触れないようにする 例:Clean The Elm Architecture(TEA) 例:Elm FRP, 遅延ストリーム, etc...

Slide 14

Slide 14 text

前半まとめ 関数型プログラミングの特徴として、ファーストクラスクロージャや参照透明な どがある 副作用が必要なときのために、参照透明でない描き方ができる言語もある 避けられるなら避けるべき

Slide 15

Slide 15 text

休憩 質問などもどうぞ 後半はSchemeについて話します。Gaucheを用いるので、暇な人は http://practical-scheme.net/gauche/download-j.html sudo apt-get install gauche などでインストールしたり、適当に遊んでみてください。

Slide 16

Slide 16 text

Schemeの入門 Lispの構文に慣れるところまでを目指します

Slide 17

Slide 17 text

インストール Schemeインタプリタの一つ、Gauche(ゴーシュ)を使います。 http://practical-scheme.net/gauche/download-j.html sudo apt-get install gauche gosh コマンドで起動できます 環境変数 GAUCHE_READ_EDIT をセットしておくと、後々の作業が楽になるかもしれませ ん export GAUCHE_READ_EDIT=1

Slide 18

Slide 18 text

Hello world! (print "Hello world!") ; セミコロンより後ろはコメントです はい、これであなたもLisperの仲間入りです!

Slide 19

Slide 19 text

値 123 3.14 "str" 今回使う値のリテラルです。これ以外にもいろいろなリテラルがあります #t #f これらはそれぞれ真と偽を表す真偽値です

Slide 20

Slide 20 text

計算 (+ 12 34) (- 1000 334) (* 10.0 -3) Lispの構文, 関数呼び出しは、このように丸括弧で囲われ、空白で区切る形で書きます 一番左の要素( + , * )が演算子、それ以外の要素は引数です (+ 12 34 56) このように、一度に複数の値を計算することもできます

Slide 21

Slide 21 text

クイズ (+) (*) ところで、この2つの式の結果はどんなものになるでしょうか? (ヒント: 和と積の単位元)

Slide 22

Slide 22 text

変数 (define x 123) x (define x+1 (+ x 1)) x+1 変数は define を使って定義します 2つ目の要素が変数名、3つめの要素が代入する値になります(正確には束縛する名前と 値、のほうがいいのでしょうか) 変数名には英数字だけでなく、様々な記号も使えます

Slide 23

Slide 23 text

ラムダ式 次に、クロージャを生成するラムダ式について触れます (lambda (left right) (+ left right)) このように lambda を使うと、2つの引数 left と right を取り、その和を返すクロージ ャーが返ります ((lambda (left right) (+ left right)) 12 34) これを呼び出すときには、丸括弧で囲った上で引数を渡します (lambda () 123) 引数を取らないクロージャも作れます

Slide 24

Slide 24 text

(lambda (a) (lambda (b) (+ a b))) ラムダ式は入れ子にでき、また外側のラムダ式の変数を内側のラムダ式で使えます (lambda () (print "Hey!") (print "Heyhey!")) lambda の後ろ側にはいくつも要素を増やすことができ、それらは前から順番に実行さ れます (lambda () (define x 123) (print x) x) ; replでは123が2回見られますが、1つ目はprint、2つ目は返り値のものです

Slide 25

Slide 25 text

クイズ 引数が1つで、返り値が「引数が1つで、渡された2つの値の和を表示するクロージャ」 であるクロージャ を書いてみましょう

Slide 26

Slide 26 text

模範解答 (lambda (x) (lambda (y) (print (+ x y))))

Slide 27

Slide 27 text

関数定義 さて、ようやく待ちに待った関数定義です。ですが、実は define と lambda で出来て しまいます (define square (lambda (x) (* x x))) (square 2) ファーストクラスクロージャーを持つ言語ならではです (define (square x) (* x x)) 上の式では define と lambda で入れ子になっていて分かりづらいため、このようなシ ンタックスシュガーが用意されています 実際のコードではこちらを使うことが多い印象です

Slide 28

Slide 28 text

関数-等価判定の方法 (equal? 1 2) (equal? "str" "str") equal? 関数を用いると、オブジェクトが等しいかどうかを判定できます 他にも eq? , eqv? などありますが、今回は省略します(気になる方はGaucheユーザー リファレンスマニュアルを見てみてください。)

Slide 29

Slide 29 text

関数-数値の比較 (= 1.0 1.0) (>= 12 45) (< 1 4 9 16) 比較の演算子は、他のプログラミング言語でよくあるようなものが使えます。また、 幾つも引数を渡してあげると、引数の順に並んでいるときのみ真を返します。ポーラ ンド記法の強いところです

Slide 30

Slide 30 text

条件分岐 (if (equal? 3 3) "true" "false") (if #f (print "true") (print "false")) (if "objectは真と評価されます" "3つ目の要素はなくても動きます") if は2つか3つの要素を受け取ります。1つ目は真偽値(真偽値を返す式)、2つ目は真の ときに実行される式、3つ目は偽のときに実行される式です 2つ目の例では、 print 関数が呼ばれるのは if で条件分岐をした後のため、 (print "true") は実行されません 他にも cond , unless , case などの条件分岐がありますが、今回は省略します(気にな る方はGaucheユーザーリファレンスマニュアルを見てみてください。)

Slide 31

Slide 31 text

クイズ 絶対値を求める関数 abs を定義してみましょう ; 組み合わせる関数や書き方 (define square (lambda (x) (* x x))) (<= 2 4) (if (equal? 1 1) (print "true") (print "false"))

Slide 32

Slide 32 text

模範解答 (define (abs x) (if (< x 0) (- x) ; xが0より小さいときは符号を反転 x)) ; xが0以上のときはxを返す

Slide 33

Slide 33 text

再帰呼び出し 関数の中で、(結果的に)自身と同じ関数を呼び出すことを再帰呼び出し、と言います これを使うことで、ループ構文などを使わずに繰り返しの処理を行えます (define (factorial n) (if (= n 0) 1 (* n (factorial (- n 1))))) 階乗を計算するプログラムです。少し複雑ですが、例えば (factorial 4) が呼ばれた 際にどういうふうに処理されるかを追っていくといいかもしれません

Slide 34

Slide 34 text

クイズ 4 3 2 1 のように与えられた値から順番に表示する関数 print-numbers を定義してみましょう

Slide 35

Slide 35 text

模範解答 (define (print-numbers n) (print n) (if (> n 1) (print-numbers (- n 1)))) ; nが1以上なら、n-1を引数に再帰呼び出しを行う

Slide 36

Slide 36 text

今回は取り扱わなかった基礎的な内容 他に覚えると良い構文 set! , cond , begin , let リスト操作に関する関数 car , cdr , cons , list , take , drop , map , for-each 今回は最重要な構文のみに絞ったため割愛しましたが、他にも沢山の関数や機能があ ります。それらはGaucheユーザーリファレンスマニュアルに載っているので、ぜひ眺 めてみてください 今回はこのスライドを見ていただきありがとうございました!

Slide 37

Slide 37 text

参考文献 1. 関数プログラミング入門 前半部分の多くで参考にさせていただきました https://www.slideshare.net/tanakh/ss-3580292 2. 関数型プログラミングはまずは純粋関数型言語を用いて、考え方から理解しよう 関数型言語プログラミングと、その他のパラダイムの違いが気になる方は読むといい かもしれません https://zenn.dev/ababup1192/articles/fb25358a570763 3. The Elm Architecture(公式ドキュメントの日本語訳) https://guide.elm-lang.jp/architecture/ 4. Gaucheユーザーリファレンスマニュアル https://practical-scheme.net/gauche/man/gauche-refj/index.html 5. 計算機プログラムの構造と解釈(SICP) https://www.vocrf.net/docs_ja/jsicp.pdf