2016年9月29日

実践common lisp第23章

intern-feature関数内でのorの使い方は良く登場する
orは論理演算なのだけど、一つ目がnilの場合は二つ目が実行されるって言うのを利用するためにorでやっているので別にifでもいい
個人的にはこれはあんまり好きじゃないので素直にunlessを使うほうがよさそうだと思っている
Pythonは実現方法は一つと言う方針だけど、Common Lispは実現方法は複数あるとでも言いましょうか

clear-database内のsetfに複数の引数を渡して一括で初期化するのもCommon Lispっぽい
可変長引数と言うか、たまにこういうふうになっているのを見かける

ここでのプログラムは相当細かいものまで分割して実装されている
実際ここまで細かく分割する必要があるかと言う話なのだけど、Common Lispではこれくらい細かくてもいいんじゃないかなって思ってます
特にincrement-countは非常に細かい
けど、この注釈にも記述があるとおり、別のデータ型を定義してincrementの方法を用意したい場合にこの記述が生きてくる
って言うのが拡張性とかそういうことに繋がってくるのだけど、このあたりの話はリファクタリングともかぶってくるので
つまり、拡張するためには現在defunで定義してあるincrement-countをdefmethodにして、さらにdefclassで別のデータ型を作ってって言う作業が必要になると言うことでも十分拡張可能なプログラムになっている

CL-PPCREを利用するメモ
http://weitz.de/cl-ppcre/
上記ページによると
(ql:quickload :cl-ppcre)
らしいので先ずQuicklispと言うものをインストールすると良さそう

https://www.quicklisp.org/beta/
上記ページによるとquicklisp.lispをダウンロードしてインストールするようだ
ちなみにファイルを入手後はCommon Lispのなんか(quicklispページではSBCLを利用していた)を起動してインストールする
その後、コマンドラインから
(load "~/quicklisp/setup.lisp")
とするとquicklispが利用可能になるので、その後cl-ppcreを読みこめば無事利用可能になる

実践common lisp第22章

loopも初心者殺しの側面があるのだけど、反面非常に強力な側面もあるんだよね
このloopの理解にもやっぱりソースコード生成の考え方ができるかどうかで理解の仕方も変わってくるような気がするんだけど
あと、まさかこれだけ高機能だと非常に非効率な実行になるとか心配する人もいるのかな
全然非効率じゃないのだけどね
これだけ高度に抽象化されたコードを記述でき、さらに効率的な実行も行えると言うことをわかって欲しいな
そしてさらにスゴイところはこんなことが誰でも可能になるような懐の深さって言うんですかね、Common Lispってやっぱりスゴイな

実践common lisp第21章

よくある名前空間の話

実践common lisp第20章

関数でもマクロでも実現できないものが特殊オペレータ
でいいのかな
QUOTEは確かに関数でもマクロでも実現できそうにない気がする
せっかくなのでQUOTEについて再度触れておくと、なんでこれが必要なのかっていうことなんですけど、Common Lispのソースコードがリストで表現されていて、そのリストの一つ目は関数名(又はマクロ、特殊オペレータ)、二つ目以降が引数っていうルールがあるから例えば
(+ 1 2 3)
はリストの一つ目の+が関数名、二つ目以降の1 2 3が引数になる
そんで例えば(あんまり有用な例が思いつかない)length関数に静的にリストを渡すとして
(length (1 2 3));間違い
と、してしまうとlength関数に渡している(1 2 3)のリストの一つ目の1が関数名として扱われてしまうから実行時にエラーになってしまう
そこでlengthに渡しているリストは一つ目が値で関数名じゃないですよって言う意味で
(length '(1 2 3))
と記述することができるようにQUOTEが存在している
QUOTEは
(quote (1 2 3))
'(1 2 3)
と等価

IFも関数だと実現できないので
あとこのPROGNって言うのが他の言語にはない珍しいもので、これは単純に言うと複数実行するものを一つにまとめるっていうかただそんだけ
インクリメントして出力するとか複数実行する場合PROGNで囲む
(let ((i 0))
(progn
(incf i)
(format t "~A~%" i)))
例えばifの第二、第三引数は一つのS式しか受け付けられないから
(if pred
(progn
(incf i)
(format t "~A~%" i))
(format t "~A~%" i))
と、PROGNで囲む
ただしwhenやunlessは暗黙でPROGNで囲まれるのでいちいち囲む必要がない
最初はめちゃくちゃややこしかったけどなれるとだんだんと分かるようになります

let、labelsも頻繁に使う
Common Lispは同じ変数名、関数名でもお構いなしに利用できるからめちゃくちゃ便利ですよね
C#だと同じ変数名使えないから匿名関数の引数でいちいち変数名を変えないといけないので

その他の特殊オペレータは正直あんまり使うことないんじゃないかなと思う
フロー制御なんて多分普通使っちゃダメなんじゃないのか
いわゆるgoto的な扱いを受けそう
そういえば昔、C#で制御構造として例外使ってる人いたんだよね
びっくりしたね、プログラムの途中でどうしても呼び出し元に制御を戻したいってことで無理やりthrowしてる人いたな、酷かったな
フロー制御はなんて言うか層が違う部分を構築する際に必要になるんじゃないかな
フレームワーク的な層とアプリケーション層と分けて作る場合に必要というかそんな気がする
多値もあんまり使わないかな

2016年9月28日

実践common lisp第19章

Common Lispと言うのは、仮想コンピュータ上で実行されているのでここまで話がややこしそうな印象を受けるんじゃないかな
Common Lispの実行環境はコマンドラインみたいなREPL(Read Eval Print Loop)で、そこではファイルのコンパイル、関数のコンパイル等すら用意されている
さらにコンパイルした関数を読み込んで実行することもできる
例えばC言語でのコンパイラ(ここで言うコンパイラと言うのはリンカなどを含めたものを言いたいのだけどどう言ったらいいかよくわかんないので、翻訳と言うよりはC言語においての提供されている一連の機能のことを指したい)の役割のみじゃなくてOS的なものまで提供されている
C言語で書いたプログラムは翻訳して実行ファイルを生成したとして、それを実行するのはOSの役割なのだけど、Common Lispの場合は実行もCommon Lispが請け負っている
だから実行時に介入できるような様々な機能が提供されている
と言うのが第2章に載っていて、第2章の末に記載されている自慢話はまあこういうことですよね、これらの賜物とでも言いましょうか

実践common lisp第18章

ここにも書いてある通りformatには信者もいればアンチもいると言う意見には賛成
初っ端、載っている例をどう捉えるかによって意見が別れると思う
一行で簡潔に記述できると感じるかわかりづらいと感じるかは人それぞれ
文字列整形で正規表現並の機能を提供しようとしているわけで、それを負担と感じる人の存在は否定できない
と、言うわけでCommon Lispで文字列を整形する場合はformat関数の第一引数にnilを渡すことで実現できると言うことを覚えておきましょう

実践common lisp第17章

クラスの定義の仕方と継承についてですね
ここで紹介されているクラスの定義はC++的に言うとパブリックなメンバ変数の記述の仕方に相当している
そして継承ですが、CLOSでの継承はメンバ関数に相当する実装は継承できず、あくまでメンバ変数のみの継承にとどまっています
CLOSでは、実装はあくまでdefmethodの役目、defclassはデータ型としての役割を受け持っていると言うことで、それぞれ一つの役割を担当しているところが他のプログラミング言語でのOOPの実現方法と異なるところです
他の言語でOOPを実装する際はdefmethodとdefclassの考え方に基づいて進めると幸せになれると思います

2016年9月26日

実践common lisp第16章

Common LispにおけるOOPへの回答がCLOSですね
一般的に言われているOOPの機能で取り上げられることが多いものは、継承、カブセル化あたりだと思うんですけどCLOSはどっちもサポートが薄いですね
このあたりが特徴的と言うところかもしれませんけど、本来のOOPとしての要求は別に継承でもカプセル化でもないはずなんだよね
いろいろ紆余曲折あっての歴史的な経緯によって継承とカプセル化が取り上げられることが多いのだけど両方共実はイマイチ使い道がないって言うかまあ別に不要って言うか
継承については、実装の継承って言うのはCLOSにおいてはまったく無視されていて、インターフェイスの継承についてのみサポートされている点が素晴らしいところですね
カプセル化なんて別にOOP使わなくてもクロージャで解決できる話でさ、C#とかC++がOOPでやっちゃったから話がややこしくなっちゃってるだけなんじゃないかなと思ってます
頻繁に目にするOOPに対する誤解みたいなものもこのカプセル化を勘違いしちゃってる点が多いと思うし
ここに一発で言い表している素晴らしい表現があるので引用させてもらうと
”オブジェクト指向の基本的なアイデアは、データ型を定義してからそのデータ型に操作を連携させることがプログラムを体系化する強力な手法になるというものだ”
と言うのはまったくその通りで、データ型に対する操作なんだよね、本当にやりたいことって
と言うことで総称関数と言うややこしそうな面倒な名称のものがここに登場します
要は様々なデータ型に対して同じ名称でそのデータ型に対する操作が定義できるというだけなんだけどね
と、言うわけでこのあたりで例示させてもらうと、よく一般的にはこういうコードを見かけるのだけど
(defclass beatles() ((name :initarg :name :accessor beatles-name)))
(let ((members (list (make-instance 'beatles :name "John Lennon")
                     (make-instance 'beatles :name "Paul McCartney")
                     (make-instance 'beatles :name "George Harrison"))))
  (mapcar (lambda(m) (format t "hi, my name is ~A~%" (beatles-name m))) members))
これって悪い例なんですよね
クラスのインスタンスそれぞれに名前を設定して、メンバー関数で名前を呼び出すとかっていうものですね
これって使い方が圧倒的に間違っていると言うか、全然問題が解決されていないって言うかまあそんな感じで、こんなことするためにわざわざクラスとか用意されてないんだよね
よく目にする解決策だとdefmethodとか言う謎の機能がまったく不要だ
じゃあどういうふうにするといいかと言うとこんな感じになる
(defclass john-lennon() ())
(defclass paul-mccartney() ())
(defclass george-harrison() ())
(defmethod get-name((m john-lennon)) "John Lennon")
(defmethod get-name((m paul-mccartney)) "Paul McCartney")
(defmethod get-name((m george-harrison)) "George Harrison")
(let ((members (list (make-instance 'john-lennon)
                     (make-instance 'paul-mccartney)
                     (make-instance 'george-harrison))))
  (mapcar (lambda(m) (format t "hi, my name is ~A~%" (get-name m))) members))
まず、必要なだけデータ型を定義する
ここでは三人分のデータ型を定義する
そしてそれぞれのデータ型に対して操作を個別に定義する
悪い例の方だとインスタンスを生成する時にどんな名前かわかっていないといけないわけよ
それって至極面倒なことなんでそうなるとこんな感じの補助関数が必要になってくる
(defun make-john-lennon-instance()
  (make-instance 'beatles :name "John Lennon"))
そしてmembersリストを生成する段階でmake-john-lennon-instance関数を呼び出すって言うのは本当に本末転倒と言うかなにやってるんだかわかったもんじゃない
素直にjohn lennonインスタンスの名前はJohn Lennonだということで話は簡単になると言う素晴らしい解決策がdefclassとdefmethodを利用することによって可能となる素晴らしいCLOS
さらに、この例で言うと継承もカプセル化も利用してない
別に継承もカプセル化も利用しなくてもOOPを十分、存分に利用できるということが分かるともっとプログラミングが楽しくなると思うのだけど
だから各インスタンにいちいち名前とか設定するなんてやめて総称関数的なやり方で表現できるように努めると幸せになれるんじゃないかなと思います

参考までにJavaScriptで同等のコードを掲載します
function beatles(name){
    this.getname = function(){
        return name;
    };
}
[new beatles("John Lennon"), new beatles("Paul McCartney"), new beatles("George Harrison")].forEach(function(a){
    console.log("Hi, my name is " + a.getname());
});

function johnlennon(){
    this.getname = function(){
        return "John Lennon";
    };
}
function paulmccartney(){
    this.getname = function(){
        return "Paul McCartney";
    };
}
function georgeharrison(){
    this.getname = function(){
        return "George Harrison";
    };
}
[new johnlennon(), new paulmccartney(), new georgeharrison()].forEach(function(a){
    console.log("Hi, my name is " + a.getname());
});

2016年9月23日

実践common lisp第15章

ポータブルなコードの書き方が載っています
ディレクトリ列挙するだけでこれだけ面倒なんだって言う感じ
.Net FrameworkでC#とかやってる人にとってはなんじゃこりゃって思うんだろうな

実践common lisp第14章

ここでの注目はやっぱりファイル名の扱いについてですね
このあたりの混沌とした感じがLispの古さや抽象度の高さを表しているなと
Lispはめちゃくちゃ古い言語だから、今どきだったら普通のものが取り入れられていないっていうところが本当に新鮮に感じますよね
この微妙に不便なところを体感して、やっぱり進化して作業がしやすくなったなと感謝する機会ですね

実践common lisp第13章

リスト操作について章が一つ割かれている理由は、Lispのソースコードはリストデータとして扱えるから
リストのデータが自在に操れると言うことは、Lispのソースコードを自在に生成できることになるので、マクロの理解が進むはず
だから、Lispでリストの操作方法を覚える目的としては、なにかの実装でリスト構造を利用すると言うよりはマクロでソースコードを生成するためというほうがより理にかなっているかも
実装で実際利用するデータ構造において、リスト構造って有利になる機会があんまりないんだよね
だからここで説明されている内容は実装ではあまりお目にかからないかも
でもマクロではお世話になることになると思う

2016年9月22日

実践common lisp第12章

ちなみにcarは
Contents of the Address part of Register numberの略らしい
cdrは
Contents of the Decrements part of Register numberの略らしい
だったらcadrは
Contents of the Address Decrements part of Register numberと言うことになり、cddddrは
Contents of the Decrements Decrements Decrements Decrements part of Register numberになるのかな

Common Lispにはリストを操作する方法が沢山用意されているのでしばらく戸惑うようになると思う
reduce,mapcarを頻繁に使うことになる
mapcarには複数のリストが渡せる
Haskellにあるzipは(mapcar #'cons list0 list1)みたいに記述できる

Common Lispが関数型もできる言語というのは、この破壊的な操作が用意されているところに現れている

2016年9月21日

実践common lisp第11章

Lispにも配列がありますよ、安心してください
高階関数で色々操作することもできます
注意点としては、破壊、非破壊がある点ですね
sortする場合は例にあるとおり真似しましょう
(setf my-sequence (sort my-sequence #'string<))

実践common lisp第10章

分数があるところが珍しい
文字列は文字の配列
文字比較、文字列比較の演算が用意されている
この章については特に触れることがないかな

2016年9月19日

実践common lisp第9章

これも非常に良いマクロの例ですね
今までのマクロの例題とは一味違う、本当にマクロでしかできない、かつ利用しがいがあるところが素晴らしい例題
ここまで良質の例題ってなかなか無いような
なにが良いかって言うとここに書いてあることってマクロ以外で実際やろうと思うと本当に面倒なんだもん
マクロが無い環境でやろうと思うと、いちいちコピペとか駆使してっていうバカバカしいことを本当にやらないといけなくて、非常に原始的な、原始人なんじゃないかって思えてくることがマクロを使うことによって素晴らしい解決策が得られる点が本当に偉大だと思う

実践common lisp第8章

書き写すしかなかったソースコードを自動で生成してくれるものと言うことかな
ソースコードを生成するプログラムを作る、作れる、素晴らしい
マクロ展開時と言うのは、プリプロセスとか言うこともある
defunとdefmacroはソックリだ
その違いを一つだけ付け加えるなら、defunは引数が評価されるが、defmacroは引数を評価しない
コンパイル時、実行時と言うのを意識できるといい
バッククオート、カンマはdefmacro内だけで利用できるわけではない、好きな時に利用できる
だから便利ならどんどん使うべきだ
「漏れをふさぐ」は結構重要、今、分からなくてもマクロを利用するなら必ず必要になる
そんな面倒ならマクロイラネって言うのは本当に勿体ないのだけどこれは仕方がない
with-gensymsはめちゃくちゃ重要だと思う、マクロ使うなら結構な頻度で利用することになると思う
これこそマクロって感じがする
と、言うのは漏れをふさぐで登場するgensymって言うのは結構頻繁に記述しないといけないわけよ
そうなるとイチイチletでgensymってやるのって本当に面倒なんだよ
だからこそのソースコード生成マクロwith-gensymsってめちゃくちゃ理にかなっている

2016年9月16日

実践common lisp第7章

いきなりわけわかんない、いつものLisperウザいって言う形容詞がぴったりの文章が始まりますけどここは一つ深呼吸して心を落ち着けて欲しいところですね
ここでは非常に重要なことを言っているんですよね
「コアに標準ライブラリを追加したもの」って言う点なんですけど、理解されていない方が多いと感じるのがこれで、言語としての機能とライブラリでの機能とごっちゃになっちゃってるんですよ
だからLispって標準ライブラリが昨今の開発環境の中ではそうとう貧相だから敬遠されているのですけど、Common Lispって別に標準ライブラリで勝負していないんですよね
標準ライブラリを含めない言語のコア機能だけで見た時、Common Lispは素晴らしいものだと言うことを理解してほしいです
残りで紹介しているものは本当に些細な例です
ここでなんじゃこりゃって思わないでほしいな
って言うか改めてここを読み返してみても酷いと思うわ
whenが標準で用意されていないとでも見受けられるこの部分は酷いよね
でも、これは逆にこういうことも自分で思い通りにすることができると言う、是非前向きに捉えていただきたいと思います
しかも追い打ちをかけるようにwhenはこうやってdefmacroで実装できるって、これ完全に追い打ちの泣き面に蜂以外のなにものでもない
この時点でこんなもん提示されて分かるわけ無いんだよね
ちなみにソースコード上でのカンマが区切り文字に見えなくなったらかなり達者になったと思ってもいいんじゃないでしょうか
ちなみにこのwhenについて説明すると
(defmacro when (condition &rest body)
  `(if ,condition (progn ,@body)))
と言うマクロは、こんなソースコード
(when (spam-p current-message)
  (file-in-spam-folder current-message)
  (update-spam-database current-message))
を、こう
(if (spam-p current-message)
  (progn
    (file-in-spam-folder current-message)
    (update-spam-database current-message)))
変形させる
まずバッククオートで囲まれているものはそのまま出力されるので
ifが出力される
次のconditionはカンマが付いているので、置き換えられる
置き換え対象はwhenマクロ呼び出し時の第一引数である(spam-p current-message)
そして次のprognもそのまま出力される
最後に残ったbodyには,@が付いているので第二引数以降のもの、つまりリストが展開されて出力される
そうすることによって自分でifなになにprognなになにって言うのを自分で入力したものとまったく同じものを得ることができるというわけですね

実践common lisp第6章

個人的にはダイナミック変数っているの?って思うのだけど
レキシカル変数のみでなんとかできるんじゃないかなって言うかそんな気がするのだが
と、言う話は置いておいて、ここでも登場するletですけど、これも変数を宣言するための関数って言うか、特殊オペレータなんですよね
これも4章の流れを引き継いでいるLispの素晴らしいところですね
あと、これ非常に使いやすい素晴らしい機能の隠すってやつですね、これって良いですね
匿名関数と非常に相性がいいと思いますね
今はどうか知らないけどC#ってこれが無理だからめちゃくちゃ面倒だった覚えがある
そしてクロージャですね
なんとなく変数に対して印象持ってるのがあるんですけど、スコープ抜けると破棄されるって言うやつ、あるじゃないですか
あれってそもそも変なんですよ、理想的には変数が破棄されるタイミングって言うのはスコープとは無関係で、不要になったら破棄されるべきものなんですよね
でも、コンパイラ作ったり、実行環境、要はGCなんですけどそういうのを用意するのが嫌だったからスコープ抜けたら破棄するってなってるんですよね
それの是非は置いておいてですね、変数は不要になったら破棄、これがLispに特有と言うわけじゃないですけどクロージャの特徴ですよね、これって
ダイナミック変数って別に使わなくてもそんなに不便無い気がするのだけど、定数も別にいらないんじゃないかな、使わないよね?
そして代入ですね、これも4章のやつね、代入するのも関数って言う素晴らしい一貫性がやっぱり何度言っても言い足りないくらい素晴らしいLispですね

2016年9月15日

実践common lisp第5章

関数ですね
defunですね
defunってなんなのかってことなんですけど、関数なんですよ、繰り返しますけど関数なんですよ
関数を定義する関数ってことなんですよね
でも本当はdefunはマクロなんですけどね
マクロについてまだ登場してないんで説明しにくいんですけど、関数を定義することも言語の機能の一部なんですよ
これがLispがすごいところでして、とにかく関数ばっかり
他の言語と圧倒的に違うところですね
Lispでは予約語が圧倒的にすくなくてですね、前章であったとおりなんでもかんでもあの形式ですまそうとしてるんで、こういうことになっちゃってるんですよ
他の言語だと関数定義はこれこれこういう風な文法で記述する、なになにはこの書式でやるっていう方法を取ってまして、それが要は高級言語ってことなんですけど、Lispはそのあたりは非常に低級な言語なんですよ
なんでもかんでも前章でのとおり記述できるようにしていますんで
んで、なんでこんなことになっているかってことなんですけど、今後登場するであろうことを先に言っておくと、関数定義すら自動生成しようって魂胆があるんですよね
早口言葉みたいですけど、関数定義をする関数とか作ることが可能になるんですよ
だからこんなことになっています
パラメータについてはここに書いてある通りです、そのままです
高階関数、匿名関数についてもこのままです

ついでなんで書いておきますけど、Lispと言うかCommon Lispは関数型じゃないっていう記述を見かけます
なんとなくLispは関数型って言う印象が強いっぽいのだけど、Lispでは関数型って言うのはSchemeのことが多くて、Common Lispは関数型もできるって言う立ち位置です
Schemeはあんまり詳しくない(SICPで扱ったことがあるだけ)から例題とか正確に記述できないのだけど、Common Lispは高階関数はfuncallでイチイチ実行しないといけないんだよね
例えばある関数に匿名関数を渡したとして、その関数を呼び出すためには、Schemeならそのまま直接引数を関数として扱えるのだけど、Common Lispの場合はfuncall、applyで呼び出さないといけない
これは前に説明した通り関数定義テーブルと変数定義テーブルが別になっているからなんだよね

defunなんですけど、気にしなければどうでもいいことなのかもしれませんけどね、マクロなんで関数を定義するソースコードを生成してるんですよね
気になる人は以下を実行するといいと思います
(macroexpand-1 '(defun f(a b) (+ a b)))
これを実行すると(defun f(a b) (+ a b))からどういうソースコードが生成されるかわかりますんで
で、Common Lispにおいて関数を定義しようと思うと要はこういうソースコードを描かないといけないんですよ
でもdefunって言うマクロっていうものが用意されてて、そのマクロを使うと
(defun f(a b) (+ a b))
でfが定義できるっていうことですよね

2016年9月14日

実践common lisp第4章

ここでは、とにかくこれですね
(function-name arguments*)
Lispのコンパイラが比較的簡単に作れる理由がこれ
ソースコード上はfunction-nameの部分がマクロだったり特殊オペレータだったりするのだけど、一見するとソースコード上では区別がつかないので、こう覚えてしまっても差し支えないかな
逆に、これだけ単純なんだということがわかればいいのではというくらい
他の言語みたいに文だ式だ二項だ単項だとか宣言だとかそういったことなんもなくてとにかく全部これで記述できるんだよね
あと、後々でてくるのだけど、いわゆる変数宣言も関数で表現するのがCommon Lispの素晴らしいところですね
特殊オペレーターについては、一言で言うと関数では実現できないものを特殊オペレーターとして実現していると言うこと
だけど、ソースコード上では区別する必要がない、し、わざわざ区別させないようにしたのだろう
例えば、JavaScriptだったとすると、JavaScriptだったらシンタックスは比較的緩めかもしれないけど、じゃあJavaScriptソースを入力として受け取るものを作ろうって思うと結構大変だと思うんだよね
例えば関数宣言、変数宣言、代入してるとか、っていうものを解析しようと思うと正規表現ではとてもじゃないけど手に負えないような代物なんですけど、Lispは相当単純にソースコードが解析できる
具体的に言うと
function f(a){
}
ってあると、まずfunctionって記述があるので次のfは関数名、aはその引数だってなるのだけど、とにかくそれが大変
対するLispはそれがない、functionって記述があるから次の単語の意味が変わるとかなくて、とにかくリストの一つ目がfunction-name、二つ目以降が引数っていうルールに一貫性があるのでパースしやすい、とにかく簡単
だからEmacsの設定にも利用されているように、そういったものには非常に利用しやすい
多分、完全に想像なんですけど、Emacsの設定ファイルってLispなんだけど、これをC言語かなんかに変換するような仕組みがあるんじゃないかなと思うんだよね
簡易のLispでそれなりの動作ができるようなものを用意しておいて、それを利用してエディタに柔軟さを持たせるわけでさ
例えばなのだけど、Apacheとかでの設定ファイルとか.htaccessとかそういうのにも使いやすいと思うんだよね、Lispの文法っていうやつは
そんでさらになんでこんなことになっているかと言うことなのだけど、読み込むのが簡単と言うことを目指したわけじゃなくて、生成が楽なことを目指したんじゃないかなと
想像してほしいのだけど、JavaScriptのソースコードを記述するプログラムを書くことがどれほど大変なことかと
逆にこれだけ単純にLispのソースコードを生成するプログラムって簡単に書けそうじゃない
マクロも特殊オペレーターもソースコード上ではまったく区別しないって言うのはソースコードを生成することが簡単になるからなわけで

2016年9月13日

実践common lisp第3章

この段階でこの章の内容を正しく理解しようとは思わないほうがいいかも
とてもじゃないけど理解できるような代物じゃないかな

先ず属性リスト、これは連想配列と似ているものですね
dic["title"] = "title"
のようなもの

formatの書式指定子でチルダが登場するところがLispっぽいところなのでこのあたりは存分に堪能しましょう

#'について、Common Lispでは名前空間が関数と変数で分かれているのでこういうものが必要になる
ここに単純にevenpと書いてしまうとそれは変数の名前空間を検索することになるのですよ
#'evenpと表記することによってevenpは関数の空間に属しているのでそちらから探してねっていうことになる
だから、evenpと言う関数と変数があっても問題ない
例えばJavaScriptなんかだと、名前空間が関数と変数でわかれていないからevenpって言う関数を定義して、さらにevenpって言う変数を定義したらevenpは変数になっちゃってevenpの関数にアクセスできなくなるわけで、どちらが良いとかじゃなくて根本的な考え方の違いでこういうことになっているところが注意点ですかね
この違いは高階関数が記述できるものでとくに違いが顕著になりますね
多分CとかC++なんかでも名前空間は別れてないんじゃないかな
C#も分かれてなくてとにかく関数、変数ごっちゃで管理して、それぞれに属性情報が付与されてそう

whereについてどうこう言っているあたりは、要はコンパイル時に判明することはコンパイル時に解決して実行時までもちこさないようにしましょうと言うことを言っている
つまりタイトルだけで検索したいときにいちいちアーティストについてとやかく言うのは無駄以外のなにものでもないと
そして普通のプログラミング言語においては、無駄でもいちいちifを動作させて、無駄と知っていてもいちいち条件分岐を実行させるのだけど、Common Lispにおいてはそんな無駄なことしなくてもいいよって言っている
厳密に言うと他のプログラミング言語でも無駄を省くことは可能なのだけど、そうするためにはいちいち条件文をソースに記述してまわらないといけないんだよね
ifで無駄な条件分岐させるか、いちいち効率的なコードを書いてまわるかのどちらか
でも、Common Lispでは標準でコード生成の仕組みが用意されているので効率的に実行できるコードをコンパイラに記述させることができるといっている
whereをマクロにすることによって、アーティストが必要なところではアーティストのみ、タイトルが必要なところではタイトルのみ検索対象とするような効率的なコードを生成することが簡単にできると言いたい
要は自慢ですね、だから訳分かんなくてもまったく気にする必要ないですけど、いつかはものにできるといいですね

実践common lisp第2章

Common Lispはとにかくオープンな技術なので、実行環境もとにかく沢山あるのですよ
そしてデファクトスタンダードが確立される程普及していないのでとりあえずここに書いてある通りのオススメを利用することが無難ですね
REPLに関してはとりあえずこういうものが利用できる程度でいいと思います
この章の最後にLispの自慢話が載っているので大きな声でへ〜と言いましょう

実践common lisp第1章

とりあえず安心してLispを使ってくれと言っているのだろうな
そして、Lisp以外のプログラミング言語は、なにかを成し遂げるための道具として利用すればいいのだけど、Lispだけはちょっと違って、何かを作るとかそういうことじゃなくて、プログラミングとはいったいなんなんだろうかと言うことが知りたいなら使うといいことがあるんじゃないかなとか、なんかひらめきそうな気がするなとかそんな類のものなんだと言いたいと思う
そして、Lispをやる場合においては他の言語の経験とか殆ど役に立たないからなにがやったことあるとか全然どうでもいいので、興味あったら読み進めましょう
例えばだけど、HaskellやるならOCamlの経験が役に立つとかErlang使うならなになにが役に立つとかそういうことが言いたいのだけど、多分どうでもいいです