SICPを何年か前に読んでいたのですが、途中まで読んでそのまま積ん読になってました。そのことをふと思い出したのでまた読み始めております。読みながらコード書く時の環境についての日記です。
SICPとは計算機プログラムの構造と解釈という本の略称。
翻訳したPDFを公開してくれている方がおり、とても感謝です。
どんな感じで読もうか
REPLを使う( Guile + rlwrap )
読みながらコード写経したくなったり問題を解きたいときがあります。そういうときはGuileのREPLを使ってます。PCはmacかchromebookか日によって。
guile
で起動して、 ,h
でヘルプ、 ,q
で終了。
$ guile scheme@(guile-user)> (+ 1 2) $1 = 3 scheme@(guile-user)> ,h Help Commands [abbrev]: ,help [all | GROUP | [-c] COMMAND] [,h] - Show help. ... scheme@(guile-user)> ,q
このままだと、 Ctrl-p
や Ctrl-a
が効かず辛いのでrlwapを使います。rlwrapは対話モードで動くようなコマンドにreadlineの機能を後付けして、コマンド履歴を Ctrl-p
で遡れるようにしたりEmacsキーバインドを使えるようにしてくれます。
guile単体で起動して Ctrl-p
すると以下のようになる。
$ guile scheme@(guile-user)> (+ 1 2) $1 = 3 scheme@(guile-user)> ; Ctrl-pを入力すると... scheme@(guile-user)> ^[[A ; Ctrl-p が使えない!
rlwrapといっしょに使う。rlwrap便利!
$ rlwrap guile scheme@(guile-user)> (+ 1 2) $1 = 3 scheme@(guile-user)> ; Ctrl-pを入力すると... scheme@(guile-user)> (+ 1 2) ; 履歴が使える!
ファイルに書いて読み込む
関数の行数が増えてくるとREPLで記述するのが辛いし間違えて消しちゃったら悲しいので、VS Codeで書いてファイルに保存してからREPLで読み込んで実行してます。
VS Codeのscheme拡張機能でコードハイライトとインデントづけを楽に。
rlwrapの -c
オプションを使うとファイル名の補完が効くので便利。
;; fib.scm (define (fib x) (cond ((= x 0) 0) ((= x 1) 1) (else (+ (fib (- x 1)) (fib (- x 2))))) )
$ rlwrap -c guile scheme@(guile-user)> (load "fib.scm") ; tabでファイル名の補完が効く! scheme@(guile-user)> (fib 5) $1 = 5
,trace
,trace使うとこんな風に表示される。
scheme@(guile-user)> ,trace (fib 5) trace: (fib 5) trace: | (fib 3) trace: | | (fib 1) trace: | | 1 trace: | | (fib 2) trace: | | | (fib 0) trace: | | | 0 trace: | | | (fib 1) trace: | | | 1 trace: | | 1 trace: | 2 trace: | (fib 4) trace: | | (fib 2) trace: | | | (fib 0) trace: | | | 0 trace: | | | (fib 1) trace: | | | 1 trace: | | 1 trace: | | (fib 3) trace: | | | (fib 1) trace: | | | 1 trace: | | | (fib 2) trace: | | | | (fib 0) trace: | | | | 0 trace: | | | | (fib 1) trace: | | | | 1 trace: | | | 1 trace: | | 2 trace: | 3 trace: 5
末尾再帰の形に書き換えると、反復処理になってることが分かる。ちなみに fib
内部で fib-iter
を記述すると ,trace
の出力にでてこない、残念。出力させる方法あるのかな。
;; fib.scm (define (fib x) (fib-iter x 1 0) ) (define (fib-iter x a b) (cond ((= x 0) b) (else (fib-iter (- x 1) (+ a b) a))) )
scheme@(guile-user)> ,trace (fib 5) trace: | (fib 5) trace: | (fib-iter 5 1 0) trace: | (fib-iter 4 1 1) trace: | (fib-iter 3 2 1) trace: | (fib-iter 2 3 2) trace: | (fib-iter 1 5 3) trace: | (fib-iter 0 8 5) trace: | 5
おしまい
こんな感じで読み進めて行こう。問題解いたらとりあえずgistに追加していこっかなぁ。