Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
初めての人のための
   Clojure
  吉田 茂(id:yshigeru)
    シーランド公国

      2010.3.20
タイトルに見覚えが…
初めての人のためのLISP
初めての人のためのLISP
シーランド公国って?
シーランド公国
   ●   北海の南端、イギリス南
       東岸から10km沖合い
       に浮かぶ自称国家
   ●   2008年現在、国連に加
       盟する192か国及びバ
       チカン市国の計193か
  ...
シーランド公国の歴史
●   1942年、海上要塞として建設、戦後廃棄
●   1967年9月2日に元イギリス陸軍少佐で海賊放送
    の運営者だったパディ・ロイ・ベーツが、イギリス放
    送法違反で訴えられたため、この要塞に目をつけ
 ...
帽子はどうした?
シルクハッター
レイトン教授
テリー伊藤さん
この帽子は…
赤シャツ?
探偵物語
前置きはここまで…
結局、アナタは誰ですか?
●   吉田 茂(ヨシダ シゲル)
●   そーり
●   id:yshigeru
●   もう4年くらいまともにLisp書いてません…
●   Clojure歴1ヶ月ちょい(久々のLisp)
ニセ者注意!!
今日の目的
 Clojureについて興味を持ってもらう
           ↓
『プログラミングClojure』を買ってもらう
           ↓
 Shiroさんに印税がガバガバ入る
           ↓
    Gaucheの開...
Clojureの謳い文句
●   Clojureはエレガントだ
●   Clojureは「Lisp・リローデッド」だ
●   Clojureは関数型言語だ
●   Clojureは並行プログラミングを簡単にする
●   ClojureはJava...
お題目
●   Clojureの基礎1
●   HTTPサーバを作ろう〜前編
●   Clojureの基礎2
●   HTTPサーバを作ろう〜後編
●   高度な話題
HTTPリクエスト
“GET /ja/clojure/test.html HTTP/1.1rn”
“Connection: closern”
“Host: foo.bar.netrn”
“rn”
HTTPレスポンス
“HTTP/1.1 200 OKrn”
“Date: Sun, 11, Jul 2010 19:39:56 GMTrn”
“Server: Apache/1.3 (Unix) mod_fastcgi/2.4.2rn”
“La...
Clojureの基礎1


              23
Javaオブジェクトの生成
(new java.util.Date)
->#<Date Thu Mar 11 10:18:22 JST
2010>


(java.util.Date.)
->#<Date Thu Mar 11 10:19:24...
メソッド呼び出し
(. (java.util.Date.) toString)
->"Thu Mar 11 10:20:39 JST 2010"


(.toString (java.util.Date.))
->"Thu Mar 11 10:...
def特殊形式
(def date (java.util.Date.))
->#'user/date


(.toString date)
->"Thu Mar 11 10:48:16 JST 2010"




               ...
関数定義
(defn fib [n]
 (cond (= n 0) 0
       (= n 1) 1
       :else (+ (fib (- n 1)) (fib (- n 2)))))
->#'user/fib


(fib 10...
let特殊形式
(let [bindings...]
  exprs...)


(let [x 1 y 2]
  (+ x y))
->3



                        28
再帰
(defn fib [n]
  (cond (= n 0) 0
        (= n 1) 1
        :else (+ (fib (- n 1)) (fib (- n 2)))))


(fib 10000)
->java....
末尾再帰
(defn fib [n0 n1 n]
  (if (zero? n)
    n0
    (fib n1 (+ n0 n1) (dec n))))


(fib 0 1 10000)
->java.lang.StackOverfl...
末尾再帰
(defn fib [n0 n1 n]
  (if (zero? n)
    n0
    (recur n1 (+ n0 n1) (dec n))))


(fib 0 1 10000)
->3364476487643178326...
末尾再帰
(defn fib [n]       ;loop特殊形式
 (loop [n0 0 n1 1 n n]
   (if (zero? n)
     n0
     (recur n1 (+ n0 n1) (dec n)))))


...
HTTPサーバを作ろう
     前編

              33
共通ヘッダの出力
(defn output-common-header [out status]
 (let [date (java.util.Date.)]
   (.println out (str "HTTP/1.0 " status "...
404 Not Found
(defn not-found [out cmd path]
 (output-common-header out "404 Not Found")
 (.println out "Content-Type: tex...
405 Method Not Allowed
(defn method-not-allowed [out cmd path]
 (output-common-header out "405 Method Not Allowed")
 (.pri...
501 Not Implemented
(defn not-implemented [out cmd path]

 (output-common-header out "501 Not Implemented")

 (.println ou...
ファイルタイプの推測
(defn guess-content-type [path]
 (cond (.endsWith path ".html") "text/html"
       (.endsWith path ".htm") "tex...
コピー
(defn copy-byte [in out]
 (loop [b (.read in)]
   (if (< b 0)
     'dobe
     (do (.write out b)
         (recur (.rea...
200 OK
(def root-dir "/export/home/shigeru")   ;ドキュメントルート

(defn do-file-response [out cmd path]

  (let [file (java.io.Fi...
Clojureの基礎2


              41
リスト、ベクタ、マップ、セット
'(1 2 3)
->(1 2 3)
[1 2 3]
->[1 2 3]
{:a 1 :b 2 :c 3}
->{:a 1, :b 2, :c 3}
#{:a :b :c}
->#{:a :b :c}
     ...
シーケンス
(first coll)
->collの最初の要素
(rest coll)
->collの残りの要素
(cons elt coll)
->collにeltを追加した新たなシーケンス



                      ...
リスト
(def x '(1 2 3))
(first x)
->1
(rest x)
->(2 3)
(cons 0 x)
->(0 1 2 3)

                     44
ベクタ
(def x [1 2 3])
(first x)
->1
(rest x)
->(2 3)       ;()はシーケンスを表す
(cons 0 x)
->(0 1 2 3)

                            ...
マップ
(def x {:a 1 :b 2 :c 3})
(first x)
->[:a 1]
(rest x)
->([:b 2] [:c 3])
(cons [:x 0] x)
->([:x 0] [:a 1] [:b 2] [:c 3])...
セット
(def x #{:a :b :c})
(first x)
->:a
(rest x)
->(:b :c)
(cons :x x)
->(:x :a :b :c)

                        47
シーケンスライブラリ
(filter pred coll)
(every pred coll)
(some pred coll)
(not-every? pred coll)
(not-any? pred coll)
(map f coll)
...
無名関数
(map (fn [x] (* x x))
     '(1 2 3 4))
->(1 4 9 16)


(fn [arg...] exprs...)
;; lambdaじゃない!!



                     ...
リスト内包表記
(for [binding-form coll-expr filter-
expr? …] expt)


(for [x '(1 2 3 4) :when (odd? x)]
 (* x x))
->(1 9)



    ...
遅延シーケンス
(lazy-seq & body)


(defn fib [n0 n1]
  (lazy-seq
   (cons n0 (fib n1 (+ n0 n1)))))


(nth (fib 0 1) 10000)
->3364...
遅延シーケンス
;; ダメな例
(defn fib [n0 n1]
  (cons n0 (fib n1 (+ n0 n1))))


(nth (fib 0 1) 10000)   ;無限ループ
->java.lang.StackOverfl...
シーケンスの現実化
(nth coll n)
(take n coll)
(doall coll)
(dorun coll)    ;副作用に興味がある場合




                               53
正規表現をシーケンスする
;; マッチのシーケンスを作り出す
(re-seq regexp string)


(re-seq #"S+" "the quick brown fox")
->("the" "quick" "brown" "fox...
分配束縛
(let [[x y] [1 2 3]]   ;値の一部にアクセスしたい
  [x y])
->[1 2]
(defn greet-author [{name :first-name}]
  (println “Hello, “ na...
HTTPサーバを作ろう
     後編

              56
ヘッダの読み込み
(defn read-header [in]
 (loop [line (.nextLine in) result {}]
   (if (= line "")
     result
     (let [[name val...
リクエストの読み込み
(defn read-request [in]
 (into {:request (.nextLine in)} (read-header in)))




                               ...
ソケットシーケンス
(defn accept-seq [sock]
 (lazy-seq
  (cons (.accept sock) (accept-seq sock))))




                             ...
サービス
(defn service [incoming]
  (let [in (java.util.Scanner. (.getInputStream incoming))
           out (java.io.PrintWrit...
メインループ
(defn http-server [port]
 (with-open [sock (java.net.ServerSocket. port)]
   (dorun
    (for [incoming (accept-seq ...
ここまでをまとめると…
●   Javaオブジェクトを簡単に生成できる
●   S式を基本としたLisp風の構文
●   あらゆるデータはシーケンス
●   シーケンスの評価は可能な限り遅延される




                   ...
高度な話題


        63
並行プログラム
●   refによる共有状態に対する協調的、同期的な変更
●   アトムによる共有状態の非協調的、同期的な変更
●   エージェントによる共有状態の非同期的な変更
●   varによるスレッドローカルな状態の管理




   ...
wc
(defn lines [in]
 (lazy-seq
  (if (.hasNextLine in)
    (cons (.nextLine in) (lines in))
    nil)))


(defn para-wc [& ...
ref
;; refの作成
(ref initial-state)
;; refの参照
(deref reference)
@reference
;; refの更新
(dosync      ;STM
  (ref-set reference ...
refバージョン
(def word-count (ref 0))
(def line-count (ref 0))


(defn wc [in]
 (for [line (lines in)]
   (let [words (count (...
アトム
;; アトムの作成
(atom initial-state options?)
;; アトムの参照
(deref an-atom)
@an-atom
;; アトムの更新
(reset! an-atom newval)

        ...
アトムバージョン
(def word-count (atom 0))
(def line-count (atom 0))


(defn wc [in]
 (for [line (lines in)]
   (let [words (count...
エージェント
;; エージェントの作成
(agent initial-value)
;; エージェントの参照
(deref an-agent)
@an-agent
;; エージェントの更新
(send an-agent update-fn & ...
エージェントバージョン
(def word-count (agent 0))
(def line-count (agent 0))


(defn wc [in]
 (for [line (lines in)]
   (let [words (...
まとめると…
●   ref:協調的、同期的
●   アトム:非協調的、同期的
●   エージェント:非協調的、非同期的




                       72
var
●   defやdefnの呼び出しは「動的なvar」を作る
●   defに初期値を与えることで、varの「ルート束縛」を
    作っていた
●   bindingマクロを使うと、varにスレッドローカルな束
    縛を作ることが出...
var
(def foo 10)
foo
->10
(binding [foo 42] foo) ;letとどう違う?
->42




                                74
var
(def foo 10)
(defn print-foo [] (println foo))


(let [foo 42] (print-foo))
|10
(binding [foo 42] (print-foo))
|42

  ...
関数のメモ化
(defn slow-double [n]
  (Thread/sleep 100)
  (* n 2))
(defn calls-slow-double []
  (map slow-double [1 2 1 2 1 2]))...
関数のメモ化
(memoize function)
;; 実装に手を加えずにメモ化
(time
 (dorun
  (binding [slow-double (memoize
slow-double)]
    (calls-slow-dou...
まとめると…
●   bindingマクロでダイナミックスコープを持つ束縛を
    作ることができる
●   bindingマクロで作る束縛は、離れた場所から関数
    に影響を及ぼすことができる(メモ化など)




          ...
マクロ
(defmacro unless [test & body]
 `(if ~test nil (do ~@body)))
(macroexpand-1
 '(unless false
    (println "foo")
    (p...
マクロ
●   foo#:自動gensym
●   (gensym prefix?):ユニークな名前の生成
●   (macroexpand-1 form):フォームの展開
●   `foo:構文クオート
●   ~foo:アンクオート
●  ...
マルチメソッド
;; マルチメソッドの定義
(defmulti name dispatch-fn)


;; 特定のメソッドの実装を与える
(defmethod name dispatch-val & fn-tail)


;; dispatc...
マルチメソッド
(defn service [incoming]
  (let [in (java.util.Scanner. (.getInputStream incoming))
           out (java.io.PrintW...
マルチメソッド
(defmulti serv (fn [out cmd path] cmd))


(defmethod serv "GET" [out cmd path]
 (do-file-response out cmd path))

...
マルチメソッド
(defn service [incoming]
 (let [in (java.util.Scanner. (.getInputStream incoming))
     out (java.io.PrintWriter. ...
まとめ
●   ClojureはCommon Lisp風のマクロを提供する
●   ディスパッチ関数を渡してマルチメソッドを定義する
    ことができる
●   マルチメソッドの呼び出し時、引数をディスパッチ関
    数に適用した結果の値で...
おわりに


       86
『プログラミングClojure』買ってね☆
           ●   Stuart Halloway 著、川
               合史朗 訳
           ●   定価:3570円(本体
               34...
Upcoming SlideShare
Loading in …5
×

Clojure

2,966 views

Published on

  • Be the first to comment

Clojure

  1. 1. 初めての人のための Clojure 吉田 茂(id:yshigeru) シーランド公国 2010.3.20
  2. 2. タイトルに見覚えが…
  3. 3. 初めての人のためのLISP
  4. 4. 初めての人のためのLISP
  5. 5. シーランド公国って?
  6. 6. シーランド公国 ● 北海の南端、イギリス南 東岸から10km沖合い に浮かぶ自称国家 ● 2008年現在、国連に加 盟する192か国及びバ チカン市国の計193か 国の中でシーランド公 国を国家承認している 国は1か国も存在しな い
  7. 7. シーランド公国の歴史 ● 1942年、海上要塞として建設、戦後廃棄 ● 1967年9月2日に元イギリス陸軍少佐で海賊放送 の運営者だったパディ・ロイ・ベーツが、イギリス放 送法違反で訴えられたため、この要塞に目をつけ 独立宣言を発表 ● イギリスは強制的に立ち退かせようと裁判に訴えた が、1968年11月25日に出された判決では、シーラ ンドがイギリスの領海外に存在し且つイギリスを含 めて周辺諸国が領有を主張していなかったことか ら、イギリス司法の管轄外とされた ● 主な外貨獲得手段は爵位の販売
  8. 8. 帽子はどうした?
  9. 9. シルクハッター
  10. 10. レイトン教授
  11. 11. テリー伊藤さん
  12. 12. この帽子は…
  13. 13. 赤シャツ?
  14. 14. 探偵物語
  15. 15. 前置きはここまで…
  16. 16. 結局、アナタは誰ですか? ● 吉田 茂(ヨシダ シゲル) ● そーり ● id:yshigeru ● もう4年くらいまともにLisp書いてません… ● Clojure歴1ヶ月ちょい(久々のLisp)
  17. 17. ニセ者注意!!
  18. 18. 今日の目的 Clojureについて興味を持ってもらう ↓ 『プログラミングClojure』を買ってもらう ↓ Shiroさんに印税がガバガバ入る ↓ Gaucheの開発が進む ↓ みんなHappy!!
  19. 19. Clojureの謳い文句 ● Clojureはエレガントだ ● Clojureは「Lisp・リローデッド」だ ● Clojureは関数型言語だ ● Clojureは並行プログラミングを簡単にする ● ClojureはJavaを歓迎する ● 他の多くの人気のある動的言語と違って、Clojure は速い
  20. 20. お題目 ● Clojureの基礎1 ● HTTPサーバを作ろう〜前編 ● Clojureの基礎2 ● HTTPサーバを作ろう〜後編 ● 高度な話題
  21. 21. HTTPリクエスト “GET /ja/clojure/test.html HTTP/1.1rn” “Connection: closern” “Host: foo.bar.netrn” “rn”
  22. 22. HTTPレスポンス “HTTP/1.1 200 OKrn” “Date: Sun, 11, Jul 2010 19:39:56 GMTrn” “Server: Apache/1.3 (Unix) mod_fastcgi/2.4.2rn” “Last-Modified: Fri, Oct 2009 14:51:04 GMTrn” “ETag: ”92004-29b-3f9001d8”rn” “Accept-Ranges: bytesrn” “Content-Length: 273rn” “Connection: closern” “Content-Type: text/htmlrn” “rn” ...(HTML)
  23. 23. Clojureの基礎1 23
  24. 24. Javaオブジェクトの生成 (new java.util.Date) ->#<Date Thu Mar 11 10:18:22 JST 2010> (java.util.Date.) ->#<Date Thu Mar 11 10:19:24 JST 2010> 24
  25. 25. メソッド呼び出し (. (java.util.Date.) toString) ->"Thu Mar 11 10:20:39 JST 2010" (.toString (java.util.Date.)) ->"Thu Mar 11 10:21:14 JST 2010" 25
  26. 26. def特殊形式 (def date (java.util.Date.)) ->#'user/date (.toString date) ->"Thu Mar 11 10:48:16 JST 2010" 26
  27. 27. 関数定義 (defn fib [n] (cond (= n 0) 0 (= n 1) 1 :else (+ (fib (- n 1)) (fib (- n 2))))) ->#'user/fib (fib 10) ->55 27
  28. 28. let特殊形式 (let [bindings...] exprs...) (let [x 1 y 2] (+ x y)) ->3 28
  29. 29. 再帰 (defn fib [n] (cond (= n 0) 0 (= n 1) 1 :else (+ (fib (- n 1)) (fib (- n 2))))) (fib 10000) ->java.lang.StackOverflowError (NO_SOURCE_FILE:0) 29
  30. 30. 末尾再帰 (defn fib [n0 n1 n] (if (zero? n) n0 (fib n1 (+ n0 n1) (dec n)))) (fib 0 1 10000) ->java.lang.StackOverflowError (NO_SOURCE_FILE:0) 30
  31. 31. 末尾再帰 (defn fib [n0 n1 n] (if (zero? n) n0 (recur n1 (+ n0 n1) (dec n)))) (fib 0 1 10000) ->3364476487643178326662161... ;; 末尾再帰を明示的に指定してあげなければならない 31
  32. 32. 末尾再帰 (defn fib [n] ;loop特殊形式 (loop [n0 0 n1 1 n n] (if (zero? n) n0 (recur n1 (+ n0 n1) (dec n))))) 32
  33. 33. HTTPサーバを作ろう 前編 33
  34. 34. 共通ヘッダの出力 (defn output-common-header [out status] (let [date (java.util.Date.)] (.println out (str "HTTP/1.0 " status "r")) (.println out (str "Date: " (.toString date) "r")) ;手抜き (.println out "Server: clj-httpd/0.1r") (.println out "Connection: closer"))) 34
  35. 35. 404 Not Found (defn not-found [out cmd path] (output-common-header out "404 Not Found") (.println out "Content-Type: text/htmlr") (.println out "r") (if (not (= cmd "HEAD")) ;GETコマンドの場合 (do (.println out "<html>r") ;doループじゃないよ (.println out "<header><title>Not Found</title></header>r") (.println out "<body><p>File not found</p></body>r") (.println out "</html>r")))) 35
  36. 36. 405 Method Not Allowed (defn method-not-allowed [out cmd path] (output-common-header out "405 Method Not Allowed") (.println out "Content-Type: text/htmlr") (.println out "r") (.println out "<html>r") (.println out "<header>r") (.println out "<title>405 Method Not Allowed</title>r") (.println out "</header>r") (.println out (str "<p>The request method " cmd " is not allowed</p>r")) (.println out "</body>r") 36 (.println out "</html>r"))
  37. 37. 501 Not Implemented (defn not-implemented [out cmd path] (output-common-header out "501 Not Implemented") (.println out "Content-Type: text/htmlr") (.println out "r") (.println out "<html>r") (.println out "<header>r") (.println out "<title>501 Not Implemented</title>r") (.println out "</header>r") (.println out "<body>r") (.println out (str "<p>The request method "           cmd          " is not implemented</p>r")) (.println out "/<body>r") 37 (.println out "/html>r"))
  38. 38. ファイルタイプの推測 (defn guess-content-type [path] (cond (.endsWith path ".html") "text/html" (.endsWith path ".htm") "text/html" :else "text/plain")) 38
  39. 39. コピー (defn copy-byte [in out] (loop [b (.read in)] (if (< b 0) 'dobe (do (.write out b) (recur (.read in)))))) 39
  40. 40. 200 OK (def root-dir "/export/home/shigeru") ;ドキュメントルート (defn do-file-response [out cmd path] (let [file (java.io.File. (str root-dir "/" path))] (if (.exists file) (let [in (java.io.FileInputStream. file)] (output-common-header out "200 OK") (.println out (str "Content-Length: " (.length file) "r")) (.println out (str "Content-Type: " (guess-content-type path) "r")) (.println out "r") (if (not (= cmd "HEAD")) (copy-byte in out)) (.close out)) (do (not-found out cmd path) (.close out))))) 40
  41. 41. Clojureの基礎2 41
  42. 42. リスト、ベクタ、マップ、セット '(1 2 3) ->(1 2 3) [1 2 3] ->[1 2 3] {:a 1 :b 2 :c 3} ->{:a 1, :b 2, :c 3} #{:a :b :c} ->#{:a :b :c} 42
  43. 43. シーケンス (first coll) ->collの最初の要素 (rest coll) ->collの残りの要素 (cons elt coll) ->collにeltを追加した新たなシーケンス 43
  44. 44. リスト (def x '(1 2 3)) (first x) ->1 (rest x) ->(2 3) (cons 0 x) ->(0 1 2 3) 44
  45. 45. ベクタ (def x [1 2 3]) (first x) ->1 (rest x) ->(2 3) ;()はシーケンスを表す (cons 0 x) ->(0 1 2 3) 45
  46. 46. マップ (def x {:a 1 :b 2 :c 3}) (first x) ->[:a 1] (rest x) ->([:b 2] [:c 3]) (cons [:x 0] x) ->([:x 0] [:a 1] [:b 2] [:c 3]) 46
  47. 47. セット (def x #{:a :b :c}) (first x) ->:a (rest x) ->(:b :c) (cons :x x) ->(:x :a :b :c) 47
  48. 48. シーケンスライブラリ (filter pred coll) (every pred coll) (some pred coll) (not-every? pred coll) (not-any? pred coll) (map f coll) (reduce f coll) 48
  49. 49. 無名関数 (map (fn [x] (* x x)) '(1 2 3 4)) ->(1 4 9 16) (fn [arg...] exprs...) ;; lambdaじゃない!! 49
  50. 50. リスト内包表記 (for [binding-form coll-expr filter- expr? …] expt) (for [x '(1 2 3 4) :when (odd? x)] (* x x)) ->(1 9) 50
  51. 51. 遅延シーケンス (lazy-seq & body) (defn fib [n0 n1] (lazy-seq (cons n0 (fib n1 (+ n0 n1))))) (nth (fib 0 1) 10000) ->3364476487643178326662161... 51
  52. 52. 遅延シーケンス ;; ダメな例 (defn fib [n0 n1] (cons n0 (fib n1 (+ n0 n1)))) (nth (fib 0 1) 10000) ;無限ループ ->java.lang.StackOverflowError (NO_SOURCE_FILE:0) 52
  53. 53. シーケンスの現実化 (nth coll n) (take n coll) (doall coll) (dorun coll) ;副作用に興味がある場合 53
  54. 54. 正規表現をシーケンスする ;; マッチのシーケンスを作り出す (re-seq regexp string) (re-seq #"S+" "the quick brown fox") ->("the" "quick" "brown" "fox") 54
  55. 55. 分配束縛 (let [[x y] [1 2 3]] ;値の一部にアクセスしたい [x y]) ->[1 2] (defn greet-author [{name :first-name}] (println “Hello, “ name)) (greet-author {:last-name “Vinge” :first-name “Vernor”}) |Hello, Vernor 55
  56. 56. HTTPサーバを作ろう 後編 56
  57. 57. ヘッダの読み込み (defn read-header [in] (loop [line (.nextLine in) result {}] (if (= line "") result (let [[name val] (re-seq #"[^:s]+" line)] (recur (.nextLine in) (cons [name val] result)))))) 57
  58. 58. リクエストの読み込み (defn read-request [in] (into {:request (.nextLine in)} (read-header in))) 58
  59. 59. ソケットシーケンス (defn accept-seq [sock] (lazy-seq (cons (.accept sock) (accept-seq sock)))) 59
  60. 60. サービス (defn service [incoming] (let [in (java.util.Scanner. (.getInputStream incoming)) out (java.io.PrintWriter. (.getOutputStream incoming) true)] (let [req (read-request in)] (let [[cmd path http] (re-seq #"S+" (req :request))] (cond (= cmd "GET") (do-file-response out cmd path) (= cmd "HEAD") (do-file-response out cmd path) (= cmd "POST") (method-not-allowed out cmd path) :else (not-implemented out cmd path)) (.close incoming))))) 60
  61. 61. メインループ (defn http-server [port] (with-open [sock (java.net.ServerSocket. port)] (dorun (for [incoming (accept-seq sock)] (.start (Thread. (fn [] (service incoming)))))))) 61
  62. 62. ここまでをまとめると… ● Javaオブジェクトを簡単に生成できる ● S式を基本としたLisp風の構文 ● あらゆるデータはシーケンス ● シーケンスの評価は可能な限り遅延される 62
  63. 63. 高度な話題 63
  64. 64. 並行プログラム ● refによる共有状態に対する協調的、同期的な変更 ● アトムによる共有状態の非協調的、同期的な変更 ● エージェントによる共有状態の非同期的な変更 ● varによるスレッドローカルな状態の管理 64
  65. 65. wc (defn lines [in] (lazy-seq (if (.hasNextLine in) (cons (.nextLine in) (lines in)) nil))) (defn para-wc [& files] (for [file files] (let [in (java.util.Scanner. (java.io.File. file))] (.start (Thread. (fn [] (dorun (wc in)))))))) (para-wc "/export/home/shigeru/httpd.clj" 65 "/export/home/shigeru/echo.clj")
  66. 66. ref ;; refの作成 (ref initial-state) ;; refの参照 (deref reference) @reference ;; refの更新 (dosync ;STM (ref-set reference new-value) 66 ...))
  67. 67. refバージョン (def word-count (ref 0)) (def line-count (ref 0)) (defn wc [in] (for [line (lines in)] (let [words (count (re-seq #"S+" line))] (dosync (ref-set line-count (inc @line-count)) (ref-set word-count (+ @word-count words)))))) ;; line-countとword-countはアトミックに更新される 67
  68. 68. アトム ;; アトムの作成 (atom initial-state options?) ;; アトムの参照 (deref an-atom) @an-atom ;; アトムの更新 (reset! an-atom newval) 68
  69. 69. アトムバージョン (def word-count (atom 0)) (def line-count (atom 0)) (defn wc [in] (for [line (lines in)] (let [words (count (re-seq #"S+" line))] (reset! line-count (inc @line-count)) (reset! word-count (+ @word-count words))))) ;; line-countとword-countが独立に更新される(同期的) 69
  70. 70. エージェント ;; エージェントの作成 (agent initial-value) ;; エージェントの参照 (deref an-agent) @an-agent ;; エージェントの更新 (send an-agent update-fn & args) 70
  71. 71. エージェントバージョン (def word-count (agent 0)) (def line-count (agent 0)) (defn wc [in] (for [line (lines in)] (let [words (count (re-seq #"S+" line))] (send line-count inc) (send word-count (fn [val] (+ val words)))))) ;; 値の更新というよりも、エージェントに対する値の更新の「依頼」 71
  72. 72. まとめると… ● ref:協調的、同期的 ● アトム:非協調的、同期的 ● エージェント:非協調的、非同期的 72
  73. 73. var ● defやdefnの呼び出しは「動的なvar」を作る ● defに初期値を与えることで、varの「ルート束縛」を 作っていた ● bindingマクロを使うと、varにスレッドローカルな束 縛を作ることが出来る ● bindingが導入する束縛はダイナミックスコープを 持つ ● varは「スペシャル変数」と呼ばれることがある ● *In*, *out*, *err* 73
  74. 74. var (def foo 10) foo ->10 (binding [foo 42] foo) ;letとどう違う? ->42 74
  75. 75. var (def foo 10) (defn print-foo [] (println foo)) (let [foo 42] (print-foo)) |10 (binding [foo 42] (print-foo)) |42 75
  76. 76. 関数のメモ化 (defn slow-double [n] (Thread/sleep 100) (* n 2)) (defn calls-slow-double [] (map slow-double [1 2 1 2 1 2])) (time (dorun (calls-slow-double))) |"Elapsed time: 656.428234 msecs" ->nil 76
  77. 77. 関数のメモ化 (memoize function) ;; 実装に手を加えずにメモ化 (time (dorun (binding [slow-double (memoize slow-double)] (calls-slow-double)))) |"Elapsed time: 217.192569 msecs" ->nil 77
  78. 78. まとめると… ● bindingマクロでダイナミックスコープを持つ束縛を 作ることができる ● bindingマクロで作る束縛は、離れた場所から関数 に影響を及ぼすことができる(メモ化など) 78
  79. 79. マクロ (defmacro unless [test & body] `(if ~test nil (do ~@body))) (macroexpand-1 '(unless false (println "foo") (println "bar"))) ->(if false nil (do (println "foo")(println "bar"))) 79
  80. 80. マクロ ● foo#:自動gensym ● (gensym prefix?):ユニークな名前の生成 ● (macroexpand-1 form):フォームの展開 ● `foo:構文クオート ● ~foo:アンクオート ● ~@foo:スプライシング・アンクオート 80
  81. 81. マルチメソッド ;; マルチメソッドの定義 (defmulti name dispatch-fn) ;; 特定のメソッドの実装を与える (defmethod name dispatch-val & fn-tail) ;; dispatch-fnを適用した結果の値によって ;; メソッドをディスパッチする 81
  82. 82. マルチメソッド (defn service [incoming] (let [in (java.util.Scanner. (.getInputStream incoming)) out (java.io.PrintWriter. (.getOutputStream incoming) true)] (let [req (read-request in)] (let [[cmd path http] (re-seq #"S+" (req :request))] (cond (= cmd "GET") (do-file-response out cmd path) (= cmd "HEAD") (do-file-response out cmd path) (= cmd "POST") (method-not-allowed out cmd path) :else (not-implemented out cmd path)) (.close incoming))))) 82
  83. 83. マルチメソッド (defmulti serv (fn [out cmd path] cmd)) (defmethod serv "GET" [out cmd path] (do-file-response out cmd path)) (defmethod serv "HEAD" [out cmd path] (do-file-response out cmd path)) (defmethod serv "POST" [out cmd path] (method-not-allowed out cmd path)) (defmethod serv :default [out cmd path] 83 (not-implemented out cmd path))
  84. 84. マルチメソッド (defn service [incoming] (let [in (java.util.Scanner. (.getInputStream incoming)) out (java.io.PrintWriter. (.getOutputStream incoming) true)] (let [req (read-request in)] (let [[cmd path http] (re-seq #"S+" (req :request))] (serv out cmd path) (.close incoming))))) 84
  85. 85. まとめ ● ClojureはCommon Lisp風のマクロを提供する ● ディスパッチ関数を渡してマルチメソッドを定義する ことができる ● マルチメソッドの呼び出し時、引数をディスパッチ関 数に適用した結果の値でディスパッチされる 85
  86. 86. おわりに 86
  87. 87. 『プログラミングClojure』買ってね☆ ● Stuart Halloway 著、川 合史朗 訳 ● 定価:3570円(本体 3400円+税) ● A5 320頁 ● ISBN 978-4-274- 06789-1 87

×