Schemeのお勉強 その1
amazonにプログラミングGaucheを注文して、届くまではこちらでscheme独習中。
文字・文字コード変換
gosh> (char->integer #\a) 97 gosh> (integer->char 97) #\a gosh> (char->integer #\あ) 12354 gosh> (integer->char 12354) #\あ
日本語もOK。ユニコードです。
index によるアクセスは XXXX-ref
gosh> (string-ref "あいうえお" 1) #\い gosh> (list-ref '(1 2 3 4) 1) 2 gosh> (vector-ref #(9 8 7) 1) 8
ドット対はリストじゃない。空リストは null?で判定。
gosh> (pair? '(1 . 2)) #t gosh> (list? '(1 . 2)) #f gosh> (list? '(1 2)) #t gosh> (null? ()) #t
そういえば commonLisp の nil に該当する定数は schemeには無いの? いまのところ出てきて無いぞ。
commonLisp では 真偽を t/nil で表現してたが、scheme では #t/#f だね。じゃあ nil = #f ってことになるのかな? うーん。
listと述語
この項、ツッコミをいただいたので書き直しです。lispの基本、リストについて整理。
(list? '(1 . 2)) => #f から、「ドット対はリストじゃない」と書いたことに対して。
buzztaikiさんのツッコミ
cdr が cons-cell な cons-cell は list ですよ。
(list? '(1 . (2 . 3))) => #t
(list? '(1 . (2 3))) => #t
(pair? '(1 2)) => #t
リストは cons-cell が繋がったもの。この基本を忘れてました。'(1 . 2)というドット対は、ただ一つの cons-cell なのでリストでは無いんですね。
あと cons のことを pair と呼ぶことを知りませんでした。ドット「対」という言い方は知ってましたが……。
'(1) のような単一要素のリストは、 '(1 . ()) と考えれば、cdr に空要素を持つのconsが繋がってるとみなせそう。(ちょっと苦しい?)
#t と #f と '()
commonLisp の nil を引き合いに出したことに対して、解説もいただきました。
SaitoAtsushiさんのコメント
#tや#fは真偽値を表現する値であり、空リストとは違う型です。 (if '() 1 2) とでもしてみれば 1 が返ることが確認できます。 #f 以外は真と解釈されます。
CommonLisp の nil は空リストと偽値を兼任していますが、 Scheme ではそれぞれ違うものなわけです。 Scheme 的な潔癖さを考えれば if の第一引数は真偽値に限定してもよさそうなものですが、そこらへんは利用上の便宜と歴史的な経緯なのでしょう。
私の lisp 原体験は xyzzy での commonLisp だったんですが、最初ブール値の表現が「T or F」でなく「T or NIL」であることに違和感を感じました。そういう意味では、schemeの真偽値はこれ以上無いくらい分かりやすいものといえますね。私の方がいつの間にかcommonLisp的な方式に染まっていたようです。多分pythonを頑張って習得したのも原因のひとつかもしれません。pythonじゃ、ブーリアンのFalse以外に、空list, 空tuple, 空辞書, 空文字列, None, そして 0 も、おおよそ「値が無い」物は皆、偽扱いですから……。
ちなみに (null? ()) という書き方は現在の Gauche では許容されますが、 Scheme 的には誤りです。(null? '()) という風に quote を付けるべきです。
quoteするかしないか迷ったところでした。試してみてたまたま通ってしまったので省略してしまいました。
貴重な突っ込みありがとうございました。勉強になります。
以上、ツッコミによる修正箇所はここまで。
プロシージャじゃなくサブルーチン(?)
schemeでは cons は
gosh> cons #<subr cons> gosh> + #<subr +> gosh> display #<subr display> gosh> do #<syntax do> gosh> if #<syntax if> gosh> dolist #<macro dolist>
ポート
解説によると標準入出力は「ポート」というデータ型に属するらしい。
current-output-port で現在の出力先が分かる。
gosh> current-output-port #<subr current-output-port> gosh> (current-output-port) #<oport (stdout) 0x107f6ee0>