Clojure å ¥éè ã«ããããã£ãããããã¥ããã Part1
æè¿ Clojure ã«ããã£ã¦ãã¾ããJVM ä¸ã§åããã¤ãã³ã¼ãã«ã³ã³ãã¤ã«å¯è½ãª Lisp æã§ã ãªããæ¸ãã¦ã¦æ¥½ãã ã§ããã¨ããããä½è ã§ãã Rich Hickey ã®ã¢ããä¸è¨ãã覧ãã ããï¼åèï¼ã»åèï¼ï¼ã
â»å è¨äºããªã³ã¯åãã«ãªã£ã¦ãã¾ã£ãã®ã§ãæ訳æç« ãåé¤ãã¾ããã
ã¨ããããã§ããã㪠Clojure ã使ã£ã¦ä»¥å Python ã§æ¸ãããã£ããããã sandmark/unmo ãåå®è£ ãã¦ã¿ã¾ããã åå¼·ç¨ãªã®ã§ééã£ã説æãããå±éºãããã¾ããããã³ãæè¿ã§ãã å®å ¨ãªã½ã¼ã¹ã³ã¼ã㯠sandmark/unmo-clojure ã«ããã¾ãã
ç®æ¬¡
æºå
- Leiningen 2.8.1
- Clojure 1.10.0
- 1.8 ã§ããããã ãã©ãè¦ããããªã£ãã¨ã©ã¼ã¡ãã»ã¼ã¸ã試ãããã£ã
- Spacemacs (develop)
- bigml/sampling
- æèã¨ã³ã¸ã³ã®é¸æã«ä½¿ããµã³ããªã³ã°ã©ã¤ãã©ãªãçµ±è¨ã¨ãããããåéã§ä½¿ãã£ã½ããã©ãä»ã«ç¢ºçãæå®ãã¦ã©ã³ãã é¸æãããã®ãè¦ã¤ãããªãã£ãâ¦
- fipp
- è¾æ¸ãã¡ã¤ã«ã®
pprint
ã«ä½¿ããçµã¿è¾¼ã¿ã®pprint
ã¯åä½ãé ãã£ã
- è¾æ¸ãã¡ã¤ã«ã®
- Sudachi
- Java ã§å®è£ ãããå½¢æ ç´ è§£æã©ã¤ãã©ãªã§ãClojure ããç´æ¥ Java ã®ã¯ã©ã¹ãå¼ã³åºãã¦ä½¿ããããããåæãã¾ããéãã®ãããæã
ã¾ãã¯ããã¸ã§ã¯ããä½ã£ã¦ã project.clj
ã®ç·¨éï¼
$ lein new app unmo $ cd unmo/ $ edit project.clj
(defproject unmo "0.1.0-SNAPSHOT" :description "A japanese legacy chatbot" :url "https://github.com/sandmark/unmo-clojure/" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :repositories [["Sonatype" "https://oss.sonatype.org/content/repositories/snapshots"]] :dependencies [[org.clojure/clojure "1.10.0"] [bigml/sampling "3.2"] [fipp "0.6.14"] [com.worksap.nlp/sudachi "0.1.1-SNAPSHOT"]] :main ^:skip-aot unmo.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
ãã¨ã¯ lein repl
ããããSpacemacs ä¸ã§ project.clj
ãéã㦠M-RET '
ã㦠cider-jack-in
ã³ãã³ããå¼ã³åºãã¾ããLisp ç³»ã®è¨èªã¯ REPL é§åéçº ãä¸è¬çã§ãã¨ãã£ã¿ã ãã§å®çµã§ããå¾è
ããããããã¾ãã
respond é¢æ°ãä½ã
Python çã§ã¯ãï¼ã¤ã®æèã¨ã³ã¸ã³ãï¼ã¤ã®ã¯ã©ã¹ã¨ãã¦å®è£ ãã¦ãã¾ãããClojure ã§ã¯ãç¹ã« Java ã¨ç¸äºéç¨ããå¿ è¦æ§ããªãéããã¯ã©ã¹ããã®ã¤ã³ã¹ã¿ã³ã¹ãçæããã¡ãªããã¯ãªãããããã®ææ°è¾¼ã¿ã§è¯ãã¿ããã§ããå®éã«ã¯ã¯ã©ã¹ãå®è£ ããæ段ãï¼ã¤ãããã®ã§ããããããã Java ã¨ã®äºææ§ã確ä¿ããããã®ãã®ã§ãã£ãããä½ã¬ãã«ãªå¦çã§ä½¿ããã®ãããã«ã¯çç±ããã£ã¦ãClojure ã®ã¹ã¿ã³ã¹ã¯ãããªæãã
ãªãã¸ã§ã¯ãæåã¯ãã¯ã©ã¹ãã¨ããåã®æ°ãããã¼ã¿åãããããå®ç¾©ãããããã«ããã®ã¤ã³ã¹ã¿ã³ã¹ã®æ±ãããä¸è¾ã«ãå¾æã¨ã¯è¨ããªãããªãã¸ã§ã¯ããæ°ä¸æ ¼ç´ããã¦ããã³ã¬ã¯ã·ã§ã³ã®èµ°æ»ãã³ãã¼ã«ã¯å¤§ããªãªã¼ãã¼ããããçºçããããªãã¸ã§ã¯ããã®ãã®ã®ãµã¤ãºãå¯å¤ã§ããä¸ãã¡ã½ããã®å®è£ ã«ãã£ã¦ã¯ãã£ã¨ã²ã©ããã¨ã«ãªãã
Clojure ã¯ã10 種é¡ã®åãæ±ã 10 åã®å½ä»¤ãããã1 種é¡ã®åãæ±ã 100 åã®å½ä»¤ãããã»ããã¯ããã«è¯ããã¨ããæ ¼è¨éããåºæ¬çã«ã¦ã¼ã¶ã¼ã«æ°ãããã¼ã¿åãå®ç¾©ãããªãããã®ããããé«æ©è½ãã¤çéãªãã¼ã¿åãç¨æãã¦ããããããã使ããå¾æ¹äºææ§ãç¶æããã¢ãããã¼ãã§ããã«ä¾¿å©ã§éããã®ã«ãªãï¼äºå®ï¼ã
ã¨ããããã§ã¯ã©ã¹ã§ã¯ãªãé¢æ°ãä½ãã¾ãã unmo/src/unmo/core.clj
ã«ããæ¸ãã¾ãã
(ns unmo.core (:gen-class)) ;; å¼æ°ã«ãã£ã¦åä½ãå¤ãããã«ãã¡ã½ãããå®ç¾©ãã ;; ãã®å ´åãä¸ãããã Map ã® :responder ã®å¤ã§åå²ãã (defmulti respond :responder) ;; :responder :what ãæå®ãããã¨ãã®æå ;; å ¥å(:input)ã®æ«å°¾ã« "ã£ã¦ãªã«ï¼" ã¨ä»å ãã ;; ãã®çµæã :response ãã¼ã«è¨å®ãã¦è¿ã (defmethod respond :what [response] (assoc response :response (str (:input response) "ã£ã¦ãªã«ï¼"))) ;; :responder ã®å¤ãæå®ãããªãã£ããã¾ãã¯å®è£ ããªãã¨ãã®æå ;; å®ç¾©ãã¦ããªã responder ãæå®ãããã¨ãã¯ãåå¨ããªããã¨ããä¾å¤ãæãã ;; æå®ãããªãã£ãã¨ãã¯ãæå®ãããã¨ããä¾å¤ãæããã ;; -> let ã¯å·¦è¾º responder ã«å³è¾º (:responder response) ãæç¸ããå¼ ;; -> Clojure ã§ã¯ Java ã®ä¾å¤ã¯ã©ã¹ãæµç¨ããã®ãå®çªããã (detmethod respond :default [response] (throw (IllegalArgumentException. (let [responder (:responder response)] (if responder (str "åå¨ããªã Responder ã§ã (" responder ")") (str "Responder ãæå®ãã¦ãã ãã"))))))
æ¸ããã SPC m s B
ã§è©ä¾¡ã» CIDER ãããã¡ã«ç§»åãã次ã®å¼ãè©ä¾¡ãã¾ãã
unmo.core> (respond {:responder :what :input "ã¦ãã¨"}) {:input "ã¦ãã¨", :responder :what, :response "ã¦ãã¨ã£ã¦ãªã«ï¼"}
respond :what
ã®å¼æ° response
ã®ä¸èº«ã¯ {:responder :what :input "ã¦ãã¨"}
ã§ãã®ã§ãæ»ãå¤ãè¦ãéãã¡ãã㨠:response ã¨ãããã¼ã追å ããã¦ãã¾ãããã ãã¡ãã£ã¨è¡¨ç¤ºãé·ãã®ã§ :response
ã ããåãåºãã¦ã¿ã¾ããããCider ã§ã¯ *1
ã¨ããã·ã³ãã«ããç´åã«è©ä¾¡ãããå¼ã®å¤ããæå³ãã¾ãã
unmo.core> (:response *1) "ã¦ãã¨ã£ã¦ãªã«ï¼"
:response
ã«æç¸ãããæååã ããåãåºããã¨ãã§ãã¾ãããClojure ã® Map ãªãã¸ã§ã¯ãããã¯ã (ãã¼ map-object)
ã¾ã㯠(map-object ãã¼)
ã¨ãããã¨ã§å¤ãåãåºããã¨ãã§ãã¾ãã
ãã®å½¢ã¯é¢æ°ã®è©ä¾¡ã¨ä¼¼ã¦ãã¾ãããï¼ å®éãããªã®ã§ããClojure ã§å¼ã³åºãå¯è½ãªãªãã¸ã§ã¯ãã¯é¢æ°ã ãã§ã¯ãªããå¤ãã®ãã¼ã¿åããèªä½ãå¼ã³åºãå¯è½ã¨ãªã£ã¦ãã¾ããä¸è¨ã§ã¯ãã¼ãå¼ã³åºããMap ãå¼æ°ã«æå®ãã¦ãã¾ãããã®ä»çµã¿ã¯ IFn
ã¨å¼ã°ãããã®ã§ã IFn
ãå®è£
ããã¦ãããã¼ã¿åãªããã¹ã¦é¢æ°ã®ããã«å¼ã³åºãã¾ãï¼ãã㯠(ifn? {})
ã (ifn? :keyword)
ãªã©ã¨ãããã¨ã§ç¢ºèªã§ãã¾ãï¼ã
ããã㯠get
é¢æ°ã使ã£ã¦ (get *1 :response)
ã¨æ¸ããã¨ãã§ãã¾ããã©ã¡ããæ¡ç¨ãããã®åºæºã¯ ClojureStyleGuide ã«æ¸ãã¦ããã¾ããï¼ãã¾èª¿ã¹ãï¼ã
ã¾ã (respond {:responder :not-found})
ã (respond {})
ãè©ä¾¡ãã¦ãä¾å¤ãæ£ããã¡ãã»ã¼ã¸ã¨ã¨ãã«æãããã¦ãããã©ãã確èªãã¦ã¿ã¦ãã ããï¼ãããã¢ãã㯠q
ãã¼ã§éãããã¨ãã§ãã¾ãï¼ã
ãªãã¡ã¯ã¿ãªã³ã°: ã¹ã¬ãããã¯ã
ã¨ãã㧠respond :what
ã¯å¦çãå±éããã¨ä»¥ä¸ã®ããã«ãªãã¾ãã
(assoc response :response (str (:input response) "ã£ã¦ãªã«ï¼")) => (assoc response :response (str "ã¦ãã¨" "ã£ã¦ãªã«ï¼")) => (assoc response :response "ã¦ãã¨ã£ã¦ãªã«ï¼") => (assoc {:responder :what :input "ã¦ãã¨"} :response "ã¦ãã¨ã£ã¦ãªã«ï¼") => {:input "ã¦ãã¨", :responder :what, :response "ã¦ãã¨ã£ã¦ãªã«ï¼"}
ã¡ãã£ã¨æ¬å¼§ãå¤ãã§ãã ãå¼ã®æå¾ã«éãæ¬å¼§ããã£ã±ãããã®ã¯ãããã©ãå¼ã®éä¸ã«æ··ãã£ã¦ãã¨èªã¿ã«ãããã¨ãã人éã®å¿çã ãå·¥å¦ã ããçºåããã®ã§ãä»ã®è¨èªã§ã¯ç¦åªã¨ããã¦ãããã¯ãã使ã£ã¦ã©ãã«ããã¾ããæã§ã©ãã«ããã¦ãè¯ãã®ã§ãããSpacemacs ã§ã¯èªåçã«æ´å½¢ãã¦ããã¾ãã
(assoc...
ã®(
ã«ã«ã¼ã½ã«ãæã£ã¦ãã£ã¦ãSPC m r t l
(ãããã¯M-x clojure-thread-last-all
) ãå®è¡
ããã¨
(defmethod respond :what [response] (->> "ã£ã¦ãªã«ï¼" (str (:input response)) (assoc response :response)))
ã®ããã«å¤æãããã¯ãã§ããããã¯è©ä¾¡æã«å
ã»ã©ã®ã³ã¼ãã«åå¤æãããã®ã§ããã人éã®ç®ã«ã¯è¦ãããããã«æãã¾ããä¾ãã° (loop (print (eval (read))))
ããã (->> (read) (eval) (print) (loop))
ã¨æ¸ãã¦ãã£ãã»ãããã£ã¨èªã¿ãããã¯ãã§ãããã㯠ã¹ã¬ãããã¯ã ã¨å¼ã°ãããã®ã§ãä»ã«ã ->
ã as->
ãªã©ãããã¾ãããããã§ã¯è©³ãã触ãã¾ãããEmacsLisp ã«ã輸å
¥ããã¦ããããã§ãä¸åº¦æ
£ããã¨ç
ã¿ã¤ãã«ãªãã¾ããç§ã¯ãã®ããã㧠Ruby ã®ã¡ã½ãããã§ã¤ã³ã Haskell ã® $
é¢æ°ãæãããªããªãã¾ããã
ãªãã¡ã¯ã¿ãªã³ã°: åé æç¸ (destructuring-bind)
CommonLisp æ¬ã§ãã On Lisp ã§ã¯ãæ§é å代å
¥ãã¨è¨³ããã¦ãã¾ããããClojure çéã§ã¯ãåé
æç¸ãã¨è¨ãã¿ããã§ãã respond :default
ã§ã¯ (:input response)
ã¨ãã形㧠:input
ã®å¤ãåãåºãã¦ãã¾ãããè¦ã¯ãããå¼æ°ã®é¨åã§ãã£ã¦ãã¾ããã¨ããæ©è½ãé£ããèããã¾ããããã£ã¦ã¿ãã¨ç°¡åã§ãã
;; :responder ã®å¤ãæå®ãããªãã£ããã¾ãã¯å®è£ ããªãã¨ãã®æå ;; å®ç¾©ãã¦ããªã responder ãæå®ãããã¨ãã¯ãåå¨ããªããã¨ããä¾å¤ãæãã ;; æå®ãããªãã£ãã¨ãã¯ãæå®ãããã¨ããä¾å¤ãæããã ;; -> Clojure ã§ã¯ Java ã®ä¾å¤ã¯ã©ã¹ãæµç¨ããã®ãå®çªããã (detmethod respond :default [{:keys [responder]}] (throw (IllegalArgumentException. (if responder (str "åå¨ããªã Responder ã§ã (" responder ")") (str "Responder ãæå®ãã¦ãã ãã")))))
response
å¼æ°ã¨ responder
ãã¼ã¯ã¼ããæ¶ããçµæã¨ã㦠let
ããªããªãã¾ããã代ããã« {:keys [...]}
ã追å ããã¦ãã¾ãã
{:keys [responder]}
ã¨ãããã©ã¼ã ã¯ãå¼æ°ã¨ãã¦åãåã£ã Map ãªãã¸ã§ã¯ãã® :responder
ãã¼ã«æç¸ããã¦ããå¤ããååã®å¤æ°ï¼ responder
ï¼ã«æç¸ããã¨ããæå³ã«ãªãã¾ãã responder
ã¸ã®æç¸ãå¼æ°ãã©ã¼ã ã§ãã£ã¦ãããã let
ãæ¶ããå
¨ä½ã®å¼ã¨ãã¦ã¯ã¤ã³ãã³ããæµ
ããªã£ã¦èªã¿ããããªã£ã¦ããâ¦â¦æ°ããããããªãããªããããªâ¦â¦ã
ã¹ã¿ã¤ã«ã¬ã¤ãã«ã¾ã ç®ãéãã¦ããªãã®ã§å¾®å¦ãªã©ã¤ã³ãªãã§ãããçãä¸åº¦ãã使ãããªãé¢æ°æ¬ä½ã®ããã«åé æç¸ããã®ã¯ãéã«èªã¿ããããæãã¦ããã¨ãè¨ãã¾ããã¨ããããç§ã¯æ £ãã ã¨æã£ã¦ä»ã®ã¨ããã¯ç©æ¥µçã«ä½¿ã£ã¦ãã¾ãã
åæ§ã« respond :what
ãåé
æç¸ã使ãã¾ãã®ã§ã調ã¹ã¦æãå ãã¦ã¿ã¦ãã ããã
次åã¯ã¡ã¤ã³ã«ã¼ããå®è£ ããã
æãã®ã»ãé·ããªã£ãã®ã§ç²ãã¾ãããä»åã¯ãã®ãããã§ãç¶ãã¾ãããã¶ãã