2010-01-22
プログラミングclojure出版間近。
clojure |
もうすぐ店頭にならぶね。
僕もd:id:leque:20100121:p1 さんみたいにこの本のレビューに参加させてもらってました。そこで見本をいただきました。
表紙は黒猫のうしろ姿。開けたら黒猫の写真がある。黒ニャー、クロニャー、クロージャ、Clojureという連想をさせるカバーになってます。しゃれを利かせてくれてます「黒猫本」だな。(笑)おまけに、無限に続く階段はどこか、遅延評価で作る無限リストをあらわしているのかもしれません。(笑)
この本は、主に他の言語取得者がclojureを知りたいときに、橋渡しになるような本に仕上がっていて、一通り網羅しているだけじゃなくて、clojureのプログラミング作法を学ぶにも最適だと思います。他の言語からlisp系を触ろうとしたら、括弧の書き方が、C風だったりすることもあるんですが、そういった部分(関数名の付けかたも含めて)の違いも理解できるでしょう。eclipseやnetbeansでもプラグインがでてるしさまざまなOSで簡単に動かせるからclojureはlisp系の入門としてもよいですが、その教科書になりうる本です。lisp系の文化だけじゃなくて、関数型言語(Clojureはlisp系の関数型言語)をjavaでさわれるということもあって、関数型言語の発想も気楽にあじわえるでしょう。
原著がclojureを開発したヒッキーさんが強く推薦するような内容でもあるし、lispハッカーでgaucheの開発者でもあり翻訳家のshiroさんが翻訳を担当しているってこともあって、翻訳本としてよくできてるからね。1.1が出たあとという状況もあって原著と出たときの違いも押えている。安心してよめる本です。
何より、clojureの一番の教科書を原著の出版から1年くらいで翻訳されたことはたいへん驚きな速さでしょう。shiroさんやオーム社のみなさんの尽力に感謝します。
2009-11-27
clojureの注意点その2
clojure |
これでも動的言語がらみのもの。partialについてです。
user> (defn foo [x y] (+ x y)) #'user/foo user> (def foo-2 (partial foo 2)) #'user/foo-2
これは fooという関数を作ってます。ここでは単純にxとyの足し算です。そしてfoo-2というのは partialを使って常にx=2にした関数になってます。その結果:
user> (foo-2 10) 12 user> (foo-2 15) 17
となります。2+10=12, 2+15=17なので間違いありません。そこで、関数fooの定義をxとyの足し算からかけ算に変えてみます。
user> (defn foo [x y] (* x y)) #'user/foo
するとどうでしょうか?
user> (foo-2 10) 12 user> (foo-2 15) 17
足し算のままです。だから、foo-2を再定義します。
user> (def foo-2 (partial foo 2)) #'user/foo-2
結果も
user> (foo-2 10) 20 user> (foo-2 15) 30 user>
となりまして。メデタシです。ここは関数の途中での変更をしたときに、partialで定義されたものがあれば、その変更が適用されないということは注意しなきゃいけないということです。
2009-11-26
clojureでの注意点
clojure |
動的言語で遅延評価を使ってるって知ってしまえば当然のことなのですが、直面しないとわかりにくいところの話です。
clojureでは 無限リストが簡単に作れるけど、その無限リストで利用している関数を変更したときにどうなるか?下の例でみてみましょう。
(defn foo [x]
(lazy-seq
(when-let [y (+ x 2)]
(cons x (foo y)))))
という単純に引数に2を足すfooという関数があります。そこでa-listを次のように定義します。
user> (def a-list (foo 0)) #'user/a-list
そして、最初の3つの要素をみてみます。
user> (take 3 a-list) (0 2 4)
ここで関数fooを変更してみます。これは単純に2倍にするものです。
(defn foo [x]
(lazy-seq
(when-let [y (* x 2)]
(cons x (foo y)))))
先のa-listの最初の3つの要素をみてみましょう。
user> (take 3 a-list) (0 2 4)
既に評価されたあとだから、変らないんです。だから、前の要素の2を足したものがあらわされたままです。じゃあその後の3つの要素もみてみましょう。
user> (take 6 a-list) (0 2 4 6 8 16)
6の次は8で2を足したままですが、8の次は2倍の16になってます。つまり、途中での関数変更で遅延評価のリストの演算も途中から変更されたために起ったことです。
このような事態を事前に知ってればたいしたことではないのですが、知らなければ、おかしいところに悩んでしまうかもしれません。
この結果があらわしているのは、関数変更後の直後のリストは変更前の関数が適用されていて、その次から変更後の関数が適用されているということです。でも、これで遅延評価がされていることもあらわしていますね。
だから、関数を途中で変更したときは、それを利用している無限リストの扱いは注意することですね。つまり、もう一度定義しなおすってことです。
user> (def a-list (foo 0)) #'user/a-list user> (take 6 a-list) (0 0 0 0 0 0)
0を2倍しても0なので永遠に0が続きます。
iterateでもおきてます。
(defn iterate-foo [x] (+ x 2))
と定義したあとに
(def b-list (iterate iterate-foo 0))
と無限リストを作ってみて3つ要素をとる
user> (take 3 b-list) (0 2 4)
さらに関数を2倍にするものにする。
(defn iterate-foo [x] (* x 2))
最初からの6つの要素を見てみましょう。
user> (take 6 b-list) (0 2 4 6 8 10)
変更後のiterate-fooとは無関係です。だから、こちらも再定義が必要です。
2009-11-19
clojureの日本語の情報源に必要なものは?
clojure |
みなさん何を求めてます?
--
clojureの日本語の情報源というのは率直に言ってあまりないし、整備も出来てない。だが、近々Programming Clojureの日本語版が川合さんの訳によって出版されることが決ってますね。そこで、折角本が出たけど、買ったけど、、、「積読」という風にならないためにも日本語の情報源の整備が重要になります。ブームというのではなくて、定着するということを考えたときには無視できないことになってます。
そこを解決するには他人の感覚が必要なところだけに、僕の想像を越えているところがあるだろうし、自分一人で解決できないところがある。だから、何を求めているか教えてください。簡単に言えば、川合本を買ったとして、実際にclojureを触るまでの橋渡しをどうしましょ?ってことですね。現在の日本語の情報源で足りないところは? ですね。要するに、clojureのプログラミングをするまでの雑務的(環境を整える)ところの段階の話です。ネットの日本語の情報源で補わなければいけないものは何か?実際にProgramming clojureの原著を読んだ人は少ないと思うけども。
個人的に、clojure japanというサイトを開いて一部インストールの方法などを書いたものと、リンクをページを作ってますが、果して、十分なのか?という疑問をもってます。
想定しているのは、興味をもって日本語版の本を買ったけど。。。という人です。彼らはどんな人が買うと思いますか? プログラムを組んだことが無い人? それとも他の言語(主にjava?)をやってる人? どこなんだろう?もし、前者ならば、netbeans+enclojureでいいのかも(一番簡単だと思う。)しれないけど、後者なら日本語の情報源に何を求めるだろうか?emacsやeclipseなど既に利用しているものでの活用?(clojureboxでも簡単だが、「日本語」を想定すると薦めにくいんだよね。)手取り足取りといった至れり尽くせりまでする必要はないと思うけど、少し敷居を下げる程度でいいとは思ってる。そこから川合本で学んでさらに情報を発信してくれる人が一人でも出てくればいいですね。
予測として成り立つのは、プログラミングに積極的に興味を持ってる人が多いのでは?というのは感じています。恐らく、最初からclojureというのは殆どいないだろうし、必要にかられて「仕方なく」clojureをするというのも殆どいないだろうからね。じゃあ彼らはどんな人だろうか?windowsで統合環境を使ってしている人?プログラミングにはwindowsは使えないと感じてlinuxやmac,bsd系に移った人?common lispやschemeを既に使ってる人?どっちにしてもまったく0から始めるという人はあまりいなさかな。
2009-11-17
map,apply and partial
clojure |
- 少し狂気に満ちた例ですが、複数の関数で評価したものを、操作する例。これだけだったら無意味なんですけど、ほかのことでやや改変して使ってる。その作った原典から適当に抽出したものです。ここでは2つの関数を使った計算例だけど、これ用の関数作成の規則に従った関数を作ればなんぼでも計算してくれる。
- common lispほど自由度がないかもしれないけど、やっぱり自由度はlispの方言らしさの特徴ですね。またこの辺(lazy-seq,partialあたり)はhaskellの影響を良く感じますね。
- add-map,subtruct-mapはある値xをリストに足したり、引いたりしている関数を返す関数になってるだけ。
- calc-map-listはそれぞれを計算してるけど、x>0までにしていることと、lstが空になれば終了する遅延リストになってる。
- max-calc-map-listは、計算したリストから、各最大値を出している。説明がめんどくさいところ。
(defn calc-map [x lst & V-fns]
(map #((%) x lst) V-fns))
(defn calc-map-list [x lst & V-fns]
(lazy-seq
(when-not (= '() lst)
(let [rest-list (rest lst)
result (apply (partial calc-map x lst)
V-fns)]
(if (< 0 x)
(cons result (apply (partial calc-map-list (dec x) rest-list)
V-fns))
(cons result (apply (partial calc-map-list 0 rest-list)
V-fns)))))))
(defn max-calc-map-list [x lst & V-fns]
(map (fn[x] (apply (fn[& y] (apply (partial map max)
y))
x))
(apply (partial calc-map-list x lst)
V-fns)))
(defn add-map []
(fn[x lst]
(map #(+ x %) lst)))
(defn subtruct-map []
(fn[x lst]
(map #(- x %) lst)))
user> (calc-map-list 3 [1 2 3] add-map subtruct-map) (((4 5 6) (2 1 0)) ((4 5) (0 -1)) ((4) (-2))) user> (max-calc-map-list 3 [1 2 3] add-map subtruct-map) ((4 5 6) (4 5) (4)) user> (calc-map-list 3 [1 2 -3] add-map subtruct-map) (((4 5 0) (2 1 6)) ((4 -1) (0 5)) ((-2) (4))) user> (max-calc-map-list 3 [1 2 -3] add-map subtruct-map) ((4 5 6) (4 5) (4))