我想我會嘗試 clojure,做一個拼圖列印從開始到目標的路徑。我的嘗試是不列印任何內容。
我知道我已經以程式方式撰寫了這個,但我不確定考慮功能性撰寫這個的最佳方式。所以我想了解為什么這不列印任何內容,如何讓條件執行 2 個動作(即:將方向添加到字串并更新位置。我在網上找到的所有示例僅執行 1 個動作),以及如何執行真正做到這一點。理想情況下,如何使我的方法起作用,以及理想的 clojure 方法是什么。
(defn -main [& args]
(def x 2)
(def y 3)
(def t_x 10)
(def t_y 15)
(while true
(let [m ""]
(cond
(> y t_y) (let [m (str m "N")])(- y 1)
(< y t_y) (let [m (str m "S")])( y 1)
(> x t_x) (let [m (str m "W")])(- x 1)
(< x t_x) (let [m (str m "E")])( x 1))
; A single line providing the move to be made: N NE E SE S SW W or NW
(println m)))))
謝謝你。
uj5u.com熱心網友回復:
該解決方案不使用回圈或遞回,而是使用序列,這是 Clojure 中的一種流行抽象:
(defn axis-steps [a b axis axis']
(concat
(cond
(< a b) (repeat (- b a) axis)
(< b a) (repeat (- a b) axis'))
(repeat nil)))
(defn path [x y tx ty]
(let [ns (axis-steps y ty "S" "N") ; = ("N" "N" nil nil nil ...)
ew (axis-steps x tx "E" "W") ; = ("E" "E" "E" nil nil nil ...)
nsew (map str ns ew) ; = ("NE" "NE" "E" "" "" "" ... )
steps (take-while seq nsew)] ; = ("NE" "NE" "E")
(clojure.string/join " " steps))) ; = "NE NE E"
(path 2 3 10 15) ; => "SE SE SE SE SE SE SE SE S S S S"
uj5u.com熱心網友回復:
- 首先,您希望將變數視為可變變數。Clojure 中的變數不能像那樣修改。除非您將它們宣告為
atoms.atoms 是特殊的可變變數。 (while true ...)非常不流行,非常C-ish。使用(loop [ ... ] ...)與組合recur。但為此,您必須了解loopand的語法recur。(let [m (str m "N")])在做任何事情之前,你的 let 表單會關閉。本地分配[m (str m "N")]僅在let表單關閉 s-]和最后一個之間時有效)。你(- y 1)在閉包之后做。在以下所有cond條款中都是這種情況。最后你這樣做(println m),因為它在(let [m ""]表單內,然后會列印"".
對于 Clojure 原子,檔案在這里 列出作為示例:
;; a var to be used for its side effects
(def a (atom 10))
;; #'user/a
(while (pos? @a)
(println @a)
(swap! a dec))
;; 10
;; 9
;; 8
;; 7
;; 6
;; 5
;; 4
;; 3
;; 2
;; 1
;;=> nil
然而,作為一名命令式程式員,人們會從a = new_value. 最好的地方是使用(reset! a new-value-of-a). 因為swap!一開始也完全誤導了我。假設你想做a = a 1。然后你必須想好,那里有什么功能:
a = func(a)?- 會的inc。那么a = a 1相當于(swap! a inc). => 這個集合a到(inc a)。但是,假設您想增加 1 以外的值,比方說增加 3。那么inc除了 之外,您還必須給出額外的引數a。假設您想a設定為(inc a 3). 然后這個交換!呼叫會是什么樣子:(swap! a incf 3)。
因此,您必須以這種方式將所有變數 ( x, y, m) 宣告為原子。并使用swap!(或對于初學者更容易reset!更新其值。最終,您必須使用偶數參考,當對可變變數的訪問應該是執行緒安全的。
使用遞回回圈的解決方案 loop [variables] <actions> recur)
啊,但我看到這不是游戲情況 - 而只是一些運行本身的行程。
對于這種情況,我將您的嘗試轉化為遞回回圈。
(loop [x 2
y 3
tx 10
ty 15
m ""]
(println m)
(cond (< ty y) (recur x (- y 1) tx ty (str m "N "))
(< y ty) (recur x ( y 1) tx ty (str m "S "))
(< tx x) (recur (- x 1) y tx ty (str m "W "))
(< x tx) (recur ( x 1) y tx ty (str m "E "))))
它列印:
S
S S
S S S
S S S S
S S S S S
S S S S S S
S S S S S S S
S S S S S S S S
S S S S S S S S S
S S S S S S S S S S
S S S S S S S S S S S
S S S S S S S S S S S S
S S S S S S S S S S S S E
S S S S S S S S S S S S E E
S S S S S S S S S S S S E E E
S S S S S S S S S S S S E E E E
S S S S S S S S S S S S E E E E E
S S S S S S S S S S S S E E E E E E
S S S S S S S S S S S S E E E E E E E
S S S S S S S S S S S S E E E E E E E E
;; => nil
現在我明白了,你t_x和t_y是目標坐標。
對于SE,NE等等這樣的組合動作,你必須引入測驗它們的子句,例如
(and (< y ty) (< x tx)) (recur ( x 1) ( y 1) tx ty (str m "E "))和其他這樣的子句。
正如我所見,tx并且ty永遠不會改變。所以把它們排除在loop-recur回圈之外:
(let [tx 10 ty 15]
(loop [x 2
y 3
m ""]
(when (not= m "") ; print only when m is not an empty string
(println m))
(cond (and (< ty y) (< x tx)) (recur ( x 1) (- y 1) (str m "NE "))
(and (< y ty) (< x tx)) (recur ( x 1) ( y 1) (str m "SE "))
(and (< ty y) (< tx x)) (recur (- x 1) (- y 1) (str m "NW "))
(and (< y ty) (< x tx)) (recur (- x 1) ( y 1) (str m "SW "))
(< ty y) (recur x (- y 1) (str m "N "))
(< y ty) (recur x ( y 1) (str m "S "))
(< tx x) (recur (- x 1) y (str m "W "))
(< x tx) (recur ( x 1) y (str m "E ")))))
它列印:
SE
SE SE
SE SE SE
SE SE SE SE
SE SE SE SE SE
SE SE SE SE SE SE
SE SE SE SE SE SE SE
SE SE SE SE SE SE SE SE
SE SE SE SE SE SE SE SE S
SE SE SE SE SE SE SE SE S S
SE SE SE SE SE SE SE SE S S S
SE SE SE SE SE SE SE SE S S S S
uj5u.com熱心網友回復:
這是我將如何撰寫它,使用我最喜歡的模板專案和庫:
(ns demo.core
(:use tupelo.core))
(defn next-x
[x x-tgt]
(cond
(< x x-tgt) {:x (inc x) :dir "E"}
(> x x-tgt) {:x (dec x) :dir "W"}
:else {:x x :dir ""}))
(defn next-y
[y y-tgt]
(cond
(< y y-tgt) {:y (inc y) :dir "N"}
(> y y-tgt) {:y (dec y) :dir "S"}
:else {:y y :dir ""}))
(defn update-state
[pos pos-goal]
(let [x-info (next-x (:x pos) (:x pos-goal))
y-info (next-y (:y pos) (:y pos-goal))
pos-next {:x (:x x-info) :y (:y y-info)}
dir-str (str (:dir y-info) (:dir x-info))
state-next {:pos-next pos-next :dir-str dir-str}]
state-next))
(defn walk-path [pos-init pos-goal]
(loop [pos pos-init]
(when (not= pos pos-goal)
(let [state-next (update-state pos pos-goal)]
(println (:dir-str state-next))
(recur (:pos-next state-next))))))
和一些單元測驗來顯示它的作業:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(dotest
(is= (next-x 0 5) {:x 1, :dir "E"})
(is= (next-x 6 5) {:x 5, :dir "W"})
(is= (next-x 5 5) {:x 5, :dir ""})
(is= (next-y 0 5) {:y 1, :dir "N"})
(is= (next-y 6 5) {:y 5, :dir "S"})
(is= (next-y 5 5) {:y 5, :dir ""}))
(dotest
(is= (update-state {:x 0, :y 0} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "NE"})
(is= (update-state {:x 1, :y 0} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "N"})
(is= (update-state {:x 2, :y 0} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "NW"})
(is= (update-state {:x 0, :y 1} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "E"})
(is= (update-state {:x 1, :y 1} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str ""})
(is= (update-state {:x 2, :y 1} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "W"})
(is= (update-state {:x 0, :y 2} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "SE"})
(is= (update-state {:x 1, :y 2} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "S"})
(is= (update-state {:x 2, :y 2} {:x 1, :y 1}) {:pos-next {:x 1, :y 1}, :dir-str "SW"}))
和最終結果:
(dotest
(let [pos-init {:x 0 :y 0}
pos-goal {:x 3 :y 5}
str-result (with-out-str
(walk-path pos-init pos-goal))]
; (println str-result) ; uncomment to print result
(is-nonblank= str-result
"NE
NE
NE
N
N")))
還有在一些功能重疊明顯next-x與next-y可能被合并,并且update-state可以清理了一點,但我想保持簡單到W / O采用了更先進的功能或輔助功能的啟動。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/377214.html
