我正在阅读Clojure的欢乐书,现在正处于多方法部分。在那本书中,他们给出了一个应该返回一个东西的例子,但是为我返回另一个东西(我已经尝试了LightTable和Emacs)。代码有点长;我尽可能地削减它,但为此道歉。它是倒数第二个命令,没有按预期返回(显示为内联)。我怎样才能正确地完成这项工作?
辅助函数非常偶然,因此您可以先跳到多方法。我把它们包括在内以防它们成为问题的可能来源。如果你需要了解更多,我会在最后添加一个说明来解释它们。
(ns joy.udp
(:refer-clojure :exclude [get]))
;; helpers
(defn beget [this proto]
(assoc this ::prototype proto))
(def clone (partial beget {}))
(defn get [m k]
(when m
(if-let [[_ v] (find m k)]
v
(recur (::prototype m) k))))
;;;;;;; compiler
(defmulti compiler :os)
(defmethod compiler ::unix [m] (get m :c-compiler))
(defmethod compiler ::osx [m] (get m :llvm-compiler))
;;;;;;; home
(defmulti home :os)
(defmethod home ::unix [m] (get m :home))
(defmethod home ::bsd [m] "/home")
;;;;;;; compile-cmd
(defmulti compile-cmd (juxt :os compiler))
(defmethod compile-cmd [:osx "gcc"] [m] (str "/usr/bin/" (get m :c-compiler)))
(defmethod compile-cmd :default [m] (str "Unsure where to locate " (get m :c-compiler)))
;;;;;;;;; hierarchy inheritence
(derive ::osx ::unix)
(derive ::osx ::bsd)
(prefer-method home ::unix ::bsd)
(derive (make-hierarchy) ::osx ::unix)
;;;;;;;;;;;; data-maps
(def unix {:os ::unix, :c-compiler "cc", :home "/home", :dev "/dev"})
(def osx (-> (clone unix)
(assoc :os ::osx)
(assoc :llvm-compiler "clang")
(assoc :home "/Users")))
(compile-cmd osx) ;; This should return "/usr/bin/gcc"
;=> "Unsure where to locate cc"
(compile-cmd unix)
;=> "Unsure where to locate cc"
*关于帮助者的注意事项:新的get
是根据ns限定关键字::prototype
重新定义的,该关键字在beget
中使用,基本上只是assoc
- 使用该关键字的地图和另一个地图作为其作为参数输入的地图的值。这个新的{:keyword {map-as-val}}对最终通过底部定义的clone
函数与osx数据映射关联。新定义的数据映射用作上面代码底部的多方法调用的参数。
我是多方法的新手,只想直观地了解多态调度在Clojure中的工作原理。我是否因为认为过于复杂而疯狂?
答案 0 :(得分:2)
(defmethod compile-cmd [::osx "gcc"] [m] (str "/usr/bin/" (get m :c-compiler)))
应该是
(defmethod compile-cmd [::osx "clang"] [m] (str "/usr/bin/" (get m :c-compiler)))
答案 1 :(得分:1)
juxt
返回一个向量,其结果是评估参数上的并置函数。如果您评估
((juxt :os compiler) osx)
你得到了
[:joy.udp/osx "clang"]
这意味着compile-cmd
会在您调用
(compile-cmd osx)
由于您在多方法中没有这些调度值,因此您将触发默认值。