

photo by whileimautomaton

9章まで読んですでに頭からすっぽ抜けてることが多かったんでサラッと復習しました。

全部書いても仕方ないんで、僕的に忘れやすいところや、難しいところをメモとしてまとめています。順番も章ごとではありません。





条件式 ifの基本的な使い方 ( if （条件式） 真 偽 ) if文でできることは一つだけだが、prognを使うと一つの式の中に余分なコマンドを押しこむことが出来る。

または、暗黙のprognであるwhenとunlessを使えばいい。 when : 条件が真の時に囲まれた式を全て実行

unless : 条件が偽の時に囲まれた式を全て実行 ( when ( 条件式） （実行したい式 ) ） cond 万能

様々な関数 返り値に真偽以外も返す関数 member : リスト中にある要素が含まれているか調べる。真偽以外にも、その値を銭湯に持つ部分のリストを返す ( member 1 '( 3 4 1 5 )) > ( 1 5 ) ( if ( member 1 '( 1 2 3 )) ' gorira ' goriragorira ) > ' gorira find-if : 制約を満たすものを取り出す、真偽を返す ( find-if #'関数 ' リスト ) ( find-if #'oddp '( 2 4 5 6 ) >5 ( if ( find-if #'oddp '( 2 4 5 6 )) ' there-is-an-odd-number ' there-is-no-odd-number ) >there-is-an-odd-number ここで出てきた#'はファンクションオペレータと呼ばれるもの。 #'関数 = ( function 関数 ) ごった煮 assoc : キーを与えるとリストを呼び出す

find : リストから与えられた要素を探す関数。findは関数の後ろに特別な引数を渡すことが出来る。 ( find ' y '(( 5 x )( 3 y )( 7 z )) :key #'cadr ) yをcadrに持つような最初の要素をリストから探し出す。それぞれ、 「：」キーワードシンボル。常に自分自身を指すシンボル 値そのもの。ここではcadr関数 remove-if-not : 渡されたリストの各要素に第一引数の関数を適用し、それが真の値を返さなかったものを除いたリストを得る？補足で Common Lisp 入門読んだら分かりやすい例があった。 ( remove-if #'oddp '( 10 11 12 13 14 15 16 17 18 19 ) ) => ( 10 12 14 16 18 ) ( remove-if-not #'oddp '( 10 11 12 13 14 15 16 17 18 19 ) ) => ( 11 13 15 17 19 ) ちょっとややこしい coerce : 文字列を文字のリストへ変換

substitute-if 与えられたテスト関数の結果によって値を置き換える関数。様々なデータ型のオブジェクトを引数としてとり、それぞれに適切な処理を行うジェネリックな関数 ( substitute-if 置き換える文字 #'条件であるテスト関数 '( リスト )) 高階関数 mapcar : 引数に他の関数とリストを受け取って、リストの要素一つ一つをその関数に引き渡す。結果は新しいリストにして返す。 ( mapcar #'sqrt '( 1 2 3 4 )) > ( 1 1.141423 1.7320508 2 2.236068 ) mapc : mapcarとは違って、リストを返さない。副作用だけ使う。

mapcan : mapcarの仲間 mapcanに渡す関数はリストを返さないといけない 返されたリストを全てappendして返す。 ( defun ingredients ( order ) ( mapcan ( lambda ( burger ) ( case burger ( single ( list ' patty )) ( double ( list ' patty ' patty )) ( double-cheese ( list ' patty ' patty ' cheese )))) order )) > ( PATTY PATTY PATTY CHEESE PATTY PATTY ) ( defun ingredients ( order ) ( mapcar ( lambda ( burger ) ( case burger ( single ( list ' patty )) ( double ( list ' patty ' patty )) ( double-cheese ( list ' patty ' patty ' cheese )))) order )) > (( PATTY ) ( PATTY PATTY CHEESE ) ( PATTY PATTY )) apply : 渡されたリスト中の要素一つ一つを別個の引数としてターゲットの関数に渡す。つまり、引数を関数に渡したいけど、リストになっているときに分解してくれるから便利。本だけだとわからなかったので、補足として Common Lisp 入門を見た。 ( apply #'関数 ' リスト ) ( mapcar #'length '( "abc" "defg" "hijkl" "mnopqr" )) => ( 3 4 5 6 ) ( apply #'+ ( mapcar #'length '( "abc" "defg" "hijkl" "mnopqr" ))) => 18

ローカル変数・関数 let : ローカル変数を定義する ( let ( 変数定義 ) 本体 ) ( let (( a 5 ) ( b 4 )) ( + a b )) > 11 let* : letでは同時に定義される変数が参照できないけど、let*はできる ( let* (( a 5 ) ( b ( + a 2 ))) b ) > 7 flet : ローカル関数を定義する。最初の２行で関数を宣言。flet内で使える。複数でも可能 ( flet (( 関数名 ( 引数 ) 関数本体 )) 本体 ) ( flet (( f ( n ) ( + n 10 ))) (( g ( n ) ( - n 3 ))) ( g ( f 5 ))) > 12 labels : fletとは違って、ローカル関数の中でも同じスコープで定義されるローカル関数が使える。 ( labels (( a ( n ) ( + n 5 )) ( b ( n ) ( + ( a n ) 6 ))) ( b 10 )) > 21

無名関数lambda 例えば数を半分にする関数を書く ( defun half ( n ) ( / n 2 )) これをmapcarするときは、halfをわざわざ呼ばないといけない ( mapcar #'half '( 2 4 6 8 10 )) lambdaなら、スッキリ書ける ( mapcar ( lambda ( n ) ( / n 2 )) '( 2 4 6 8 10 )) 16章でマクロは詳しく書いてあるらしい。楽しみ。

8章のコードをちゃんと読む。 と言いつつ、あんまりちゃんと読んでない。ソースコード全体はリンク先。

http://landoflisp.com/wumpus.lisp

make-city-edges関数 ( defun make-city-edges () ( let* (( nodes ( loop for i from 1 to *node-num* collect i )) ( edge-list ( connect-all-islands nodes ( make-edge-list ))) ( cops ( remove-if-not ( lambda ( x ) ( zerop ( random *cop-odds* ))) edge-list ))) ( add-cops ( edges-to-alist edge-list ) cops ))) edges-to-alist関数 ( defun edges-to-alist ( edge-list ) ( mapcar ( lambda ( node1 ) ( cons node1 ( mapcar ( lambda ( edge ) ( list ( cdr edge ))) ( remove-duplicates ( direct-edges node1 edge-list ) :test #'equal )))) ( remove-duplicates ( mapcar #'car edge-list )))) add-cops関数 ( defun add-cops ( edge-alist edges-with-cops ) ( mapcar ( lambda ( x ) ( let (( node1 ( car x )) ( node1-edges ( cdr x ))) ( cons node1 ( mapcar ( lambda ( edge ) ( let (( node2 ( car edge ))) ( if ( intersection ( edge-pair node1 node2 ) edges-with-cops :test #'equal ) ( list node2 ' cops ) edge ))) node1-edges )))) edge-alist )) Lispは括弧ばっかりで見た瞬間げんなりするようなことが多かったけど、インデントに意味があるようなので、慣れたらスラスラ読めるようになるのかも？ただletとかlambdaが入り組むと、括弧がどこで終わっているのかを追うのが難しい。構造を見てから読むようにしたいと思います。