type holyshared = Engineer<mixed>

PHP、Hack、Ruby、OCaml、Rust、Javascript周りの技術ブログ

Scheme手習い読み終わった

定理証明手習いを途中まで読んでいたのですが、読む前におすすめされていたのと、近所の本屋に一冊だけあったので読みました。

最初にちょっとだけ読み始めて、載っているコードが非常に少なく、写経しなくても覚えれそうと思い、 ちょうど真ん中ぐらいの内容まで、読むだけにしていました。

しかし、だんだん読むのに飽きてきたので、写経するように変えていくようにしました。

本の内容

基本的にSchemeになれるようにするためのドリルぽい印象です。
実用的なコードはないですね。

  • 7割ぐらいリスト操作
  • 再帰するコードがひたすら出てくる
    • OCamlとかやっている人はそんなに難しくない
  • ドリル形式、読み手に質問しつつ、書く関数の仕様をはっきりさせていくスタイル
    • 仕様わかったよね?、もう書けるよね?、じゃあ書いてみようのステップ
  • cond, car, cdr, consをよく使う、リストの再帰だから仕方ない
  • 1つの関数が大したことないので、サクサク進める

写経の仕方

写経するに準備したもの

用意したのはSchemeの処理系だけです。 SchemeLISPはやったことなかったので、インストールが楽そうなRacketにしました。

写経の仕方

Githubリポジトリ作って、写経したその日にやったことをREADME.mdに雑に書いていく感じのスタイルです。

コードは本の内容を移すのではなく、期待する動作をするコードを書いていきました。
なので、本のこういう関数に引数x,yを与えると、結果はどうなるか、という仕様部分しか見てないです。

そして、書いた結果と本のコードを見比べて、条件が足りているか答え合わせをする感じです。

感想

Scheme入門的にはいいかなと思います。

プログラミングやったことない人にはいいかもしれないですが、ただ、内容が割と単調なので、途中で飽きる人出そうな気はします。

ちなみにSchemeやったことなかった人の意見です。

OCamlと比べて、Scheme再帰が書きにくいと感じました。

これは、OCamlでListの再帰を書くとき、自分は普段パターンマッチを使用していて、特定の条件に対して、それぞれコードを書いていくスタイルなのですが、Schemeの場合はリストが空の場合はこう、リストの先頭がこれの場合こうと手順を意識しないといけない印象を受けた為です。

この例は、あんまりよくないです。

OCaml

(* [] ->, hd::tail ->の順番を変えても問題ない *)
let print_all l =
  let rec print_all l =
    match l with           (* matchじゃなくて、functionの方がいいかも *)
      | [] -> ()           (* 空の場合 *)
      | hd::tail ->        (* 空でない場合 *)
        print_endline hd;
        print_all tail in
  print_all l

Scheme

(define print_all
  (lambda (l)
    (cond 
      ((null? l) values)         ; null?から先に確認
      (else (begin
        (display (car l))
        (newline)
        (print_all (cdr l)))))
))

書いた方が覚えやすいです

途中から写経し始めたわけですが、読んでいるだけだと記憶の定着率が悪いのを再認識しました。
書けるだろうと、書き始めて見ても、もどう書けばいいのかなかなか頭から出ませんでした。