Joy of Clojure example not working

275 views
Skip to first unread message

gamma235

unread,
May 19, 2014, 9:39:26 AM5/19/14
to clo...@googlegroups.com
Hi guys, I am working through the pre-release second edition of Joy of Clojure's section on multi-methods (section 9.2.~ : pg. 313), and am getting different outputs from what they have printed in the book. I could just skip over it, but I really want to understand this stuff. Could someone tell me how to get the (compile-cmd osx) call at the end of the code to produce the expected output:  "/usr/bin/gcc" ? I have commented out redundancy and moved a couple of lines for readability. Thanks in advance! 

J
(ns joy.udp
  (:refer-clojure :exclude [get]))

(defn beget [this proto]
  (assoc this ::prototype proto))

(defn get [m k]
  (when m
    (if-let [[_ v] (find m k)]
      v
      (recur (::prototype m) k))))

(def put assoc)

;;;;;;; compiler
(defmulti compiler :os)
(defmethod compiler ::unix [m] (get m :c-compiler))
(defmethod compiler ::osx [m] (get m :llvm-compiler))

(def clone (partial beget {}))
 
(def unix {:os ::unix, :c-compiler "cc", :home "/home", :dev "/dev"})
 
(def osx (-> (clone unix)
             (put :os ::osx)
             (put :llvm-compiler "clang")
             (put :home "/Users")))

;;;;;;; home
(defmulti home :os)
(defmethod home ::unix [m] (get m :home))
(defmethod home ::bsd [m] "/home")
 
;; the error on the call to (home osx) is contingent upon toggling the following lines. 
;(derive ::osx ::unix)
;(derive ::osx ::bsd)
(prefer-method home ::unix ::bsd)
;(remove-method home ::bsd)   
(derive (make-hierarchy) ::osx ::unix) 

;;;;;;; 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)))
;;;;;;;;;;;;;;;;;;;;;;

(home osx) 
;=> java.lang.IllegalArgumentException: No method in multimethod 'home' for dispatch value: :joy.udp/osx …
 ;; Should be: ;=> "/Users"

(compile-cmd osx)
;=> "Unsure where to locate cc"     
 ;; Should be: ;=> "/usr/bin/gcc"
 
(compile-cmd unix)
;=> "Unsure where to locate cc"
;; this is the expected output 

Rob Day

unread,
May 19, 2014, 9:44:12 AM5/19/14
to clo...@googlegroups.com
It looks like it expects the keyword :osx, not the symbol osx. Could
that be the issue?
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+u...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--
Robert K. Day
rober...@merton.oxon.org

gamma235

unread,
May 19, 2014, 10:13:06 AM5/19/14
to clo...@googlegroups.com, rober...@merton.oxon.org
It looks like it expects the keyword :osx, not the symbol osx. Could 
that be the issue? 

Thanks for the suggestion, but when I try that instead, I get this error:

java.lang.IllegalArgumentException: No method in multimethod 'compiler' for dispatch value: null

I kind of feel it might be a typo in the compile-cmd function, cause instead of a sybol it is listing a vector with a name-spaced symbol and a string:  [::osx "gcc"]. I think this form might have to do something with juxt in  (defmulti compile-cmd (juxt :os compiler))
But I admit that I don't really understand what is going on here, as the book doesn't go all that far in explaining juxt, using keys as functions and how it relates to the defmethod syntax taking a vector in the beginning.

Greg D

unread,
May 19, 2014, 12:06:30 PM5/19/14
to clo...@googlegroups.com
The second edition of Joy of Clojure, MEAP v10 shows the same error and progressive solution about half way down pdf-page 318 in section 9.2.4.

gamma235

unread,
May 19, 2014, 7:38:00 PM5/19/14
to clo...@googlegroups.com
I actually just wanna know why I need to use derive so many times. Isn't there a core function/macro where I can derive and set hierarchy all at once? I'm just looking for a more efficient way. My bad for not stating that more clearly in the original post.

The real problem though is the last two calls to compile-cmd. I've been messing with it for a couple of days so any help there would be well appreciated.

Thanks

J

Message has been deleted

Greg D

unread,
May 20, 2014, 1:18:08 PM5/20/14
to clo...@googlegroups.com
Yes, the examples in the book are missing some lines. I think the following log shows what they were going for:

joy.udp=> (remove-method compiler ::osx)
joy.udp=> (def unix (into unix {::c-compiler "/usr/bin/gcc"}))
joy.udp=> (def osx (into osx {:c-compiler "gcc"}))
oy.udp=> osx
{:home "/Users", :llvm-compiler "clang", :os :joy.udp/osx, :joy.udp/prototype {:home "/home", :os :joy.udp/unix, :c-compiler "cc", :dev "/dev"}, :c-compiler "gcc"}
joy.udp=> unix
{:home "/home", :joy.udp/c-compiler "/usr/bin/gcc", :os :joy.udp/unix, :c-compiler "cc", :dev "/dev"}
joy.udp=> (compiler osx)
"gcc"
joy.udp=> (compile-cmd osx)
"/usr/bin/gcc"

About your question:

Isn't there a core function/macro where I can derive and set hierarchy all at once?
Such a function would need to know in advance what hierarchy you want to construct. If you have a desired pattern of hierarchy that you want to reuse, you could define a function to create it using "derive" and optionally "make-hierarchy".

gamma235

unread,
May 20, 2014, 11:06:09 PM5/20/14
to clo...@googlegroups.com
This did it Greg,

Thanks a lot.

Chouser

unread,
Aug 15, 2021, 12:17:56 AM8/15/21
to Clojure
In this case, I think the git repo has correct code where the book does not; "clang" instead of "gcc":

(defmethod compile-cmd [::osx "gcc"] [m]
  (str "/usr/bin/" (get m :c-compiler)))

...should instead be...

(defmethod compile-cmd [::osx "clang"] [m]   ;; Match the vector exactly

  (str "/usr/bin/" (get m :c-compiler)))
Reply all
Reply to author
Forward
0 new messages