Upgrade to Pro — share decks privately, control downloads, hide ads and more …

関数型プログラミングの考え方について / Scheme入門

soukouki
September 14, 2021

関数型プログラミングの考え方について / Scheme入門

2021-09-12に開催された低レベル勉強会で使用したスライドに、追記したものです。

Scheme入門はLambda Chipを触れるレベルまで解説することを目標としており、基礎的な内容の多くを割愛しています。

soukouki

September 14, 2021
Tweet

More Decks by soukouki

Other Decks in Programming

Transcript

  1. 計算 (+ 12 34) (- 1000 334) (* 10.0 -3)

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

    x+1 変数は define を使って定義します 2つ目の要素が変数名、3つめの要素が代入する値になります(正確には束縛する名前と 値、のほうがいいのでしょうか) 変数名には英数字だけでなく、様々な記号も使えます
  3. ラムダ式 次に、クロージャを生成するラムダ式について触れます (lambda (left right) (+ left right)) このように lambda

    を使うと、2つの引数 left と right を取り、その和を返すクロージ ャーが返ります ((lambda (left right) (+ left right)) 12 34) これを呼び出すときには、丸括弧で囲った上で引数を渡します (lambda () 123) 引数を取らないクロージャも作れます
  4. (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つ目は返り値のものです
  5. 関数定義 さて、ようやく待ちに待った関数定義です。ですが、実は define と lambda で出来て しまいます (define square (lambda

    (x) (* x x))) (square 2) ファーストクラスクロージャーを持つ言語ならではです (define (square x) (* x x)) 上の式では define と lambda で入れ子になっていて分かりづらいため、このようなシ ンタックスシュガーが用意されています 実際のコードではこちらを使うことが多い印象です
  6. 関数-等価判定の方法 (equal? 1 2) (equal? "str" "str") equal? 関数を用いると、オブジェクトが等しいかどうかを判定できます 他にも

    eq? , eqv? などありますが、今回は省略します(気になる方はGaucheユーザー リファレンスマニュアルを見てみてください。)
  7. 関数-数値の比較 (= 1.0 1.0) (>= 12 45) (< 1 4

    9 16) 比較の演算子は、他のプログラミング言語でよくあるようなものが使えます。また、 幾つも引数を渡してあげると、引数の順に並んでいるときのみ真を返します。ポーラ ンド記法の強いところです
  8. 条件分岐 (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ユーザーリファレンスマニュアルを見てみてください。)
  9. 模範解答 (define (abs x) (if (< x 0) (- x)

    ; xが0より小さいときは符号を反転 x)) ; xが0以上のときはxを返す
  10. 再帰呼び出し 関数の中で、(結果的に)自身と同じ関数を呼び出すことを再帰呼び出し、と言います これを使うことで、ループ構文などを使わずに繰り返しの処理を行えます (define (factorial n) (if (= n 0)

    1 (* n (factorial (- n 1))))) 階乗を計算するプログラムです。少し複雑ですが、例えば (factorial 4) が呼ばれた 際にどういうふうに処理されるかを追っていくといいかもしれません
  11. 模範解答 (define (print-numbers n) (print n) (if (> n 1)

    (print-numbers (- n 1)))) ; nが1以上なら、n-1を引数に再帰呼び出しを行う
  12. 今回は取り扱わなかった基礎的な内容 他に覚えると良い構文 set! , cond , begin , let リスト操作に関する関数

    car , cdr , cons , list , take , drop , map , for-each 今回は最重要な構文のみに絞ったため割愛しましたが、他にも沢山の関数や機能があ ります。それらはGaucheユーザーリファレンスマニュアルに載っているので、ぜひ眺 めてみてください 今回はこのスライドを見ていただきありがとうございました!
  13. 参考文献 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