Thumbnail's answer很好,我也不想分散注意力,但是你的小練習也給了我玩Clojure那種我無法抗拒的口齒不清的機會。
;Agree that unit vectors are more convenient to work with than cardinal directions
(def north [0 1])
(def east [1 0])
(def south [0 -1])
(def west [-1 0])
;Just for a taste of macros
(defmacro name-value-map [& xs]
`(zipmap ~(mapv name xs) (vector [email protected])))
(def direction->heading (name-value-map north east south west))
(def heading->direction (clojure.set/map-invert direction->heading))
;Robot commands just return an updated structure
(defn left [robot]
(update-in robot [:heading] (fn [[dx dy]] [(- 0 dy) dx])))
(defn right [robot]
(update-in robot [:heading] (fn [[dx dy]] [dy (- 0 dx)])))
(defn move [robot]
(update-in robot [:position] (partial mapv + (:heading robot))))
;Report and return unchanged
(defn report [robot]
(println "Robot at" (:position robot)
"facing" (heading->direction (:heading robot)))
robot)
;Create
(defn place [x y heading]
{:position [x y] :heading heading})
與那些在地方
現在你已經幾乎有一個小型的DSL語言通過線程宏觀
(-> (place 3, 3, north) report move report left report move report)
;Printed Output:
;Robot at [3 3] facing north
;Robot at [3 4] facing north
;Robot at [3 4] facing west
;Robot at [2 4] facing west
;Return Value:
;{:position [2 4], :heading [-1 0]}
事實上,如果你有一個文件你與內容
信任
(def sample-file-contents "(place 3, 3, north) move left move")
你可以在數據作爲一種形式
閱讀
交織一些報告(在REPL *1
是以前的值)
user=> (interleave *1 (repeat 'report))
((place 3 3 north) report move report left report move report)
粘性在穿線宏
user=> (cons '-> *1)
(-> (place 3 3 north) report move report left report move report)
而且eval
審視你們對於相同的輸出如上
user=> (eval *1)
;Printed Output
;Robot at [3 3] facing north
;Robot at [3 4] facing north
;Robot at [3 4] facing west
;Robot at [2 4] facing west
;Return Value:
;{:position [2 4], :heading [-1 0]}
要這樣設置一個位更恰當不需要具有良好的解析庫
(require '[instaparse.core :as insta])
(require '[clojure.tools.reader.edn :as edn])
(def parse (insta/parser "
<commands> = place (ws command)*
<command> = place | unary-command
place = <'place '> location <', '> direction
unary-command = 'left' | 'right' | 'move' | 'report'
number = #'[0-9]+'
location = number <', '> number
direction = 'north' | 'east' | 'west' | 'south'
<ws> = <#'\\s+'> "))
(defn transform [parse-tree]
(insta/transform
{:number edn/read-string
:location vector
:direction direction->heading
:place (fn [[x y] heading] #(place x y heading))
:unary-command (comp resolve symbol)}
parse-tree))
(defn run-commands [[init-command & more-commands]]
(reduce (fn [robot command] (command robot)) (init-command) more-commands))
現在太多額外的努力,我們已經放棄了要求的括號(以及包含一些樣本換行符),在REPL重新定義了樣本文件
(def sample-file-contents "place 3, 3, north report
move report
left report
move report")
並再次顯示中間結果
user=> (parse sample-file-contents)
([:place [:location [:number "3"] [:number "3"]] [:direction "north"]] [:unary-command "report"]
[:unary-command "move"] [:unary-command "report"]
[:unary-command "left"] [:unary-command "report"]
[:unary-command "move"] [:unary-command "report"])
user=> (transform *1)
(#< [email protected]> #'user/report
#'user/move #'user/report
#'user/left #'user/report
#'user/move #'user/report)
user=> (run-commands *1)
;Printed Output:
;Robot at [3 3] facing north
;Robot at [3 4] facing north
;Robot at [3 4] facing west
;Robot at [2 4] facing west
;Return Value:
;{:position [2 4], :heading [-1 0]}
我也不太UND知道這個問題。如果我是正確的,那麼當你創建一個對象時,你想要找到一種方法來存儲座標和球員的「狀態」,就像你在面向對象的編程語言中所做的那樣? – albusshin
沒錯,所以我想存儲座標。 基本上,它從地方命令開始,然後移動幾次和報告... 我應該如何存儲x,y,方向? – mark
在函數式語言中,您不應該像在面向對象編程中那樣思考。爲什麼不簡單使用地圖 – albusshin