Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
692 views
in Technique[技术] by (71.8m points)

functional programming - Clojure- Defining a variable inside of a function?

I have this variable, hand, that works just fine when I define it on its own.

(def yourHand
(map
 ;;fn
 #(let [x %]
       (cond
         ;;hearts
         (< x 10) (* x -1)
         (< x 13) -10
         ;;diamonds
         (< x 23) (* (mod x 13) -1)
         (< x 26) -10
         ;;clubs
         (< x 36) (mod x 13)
         (< x 39) 10
         ;;spades
         (< x 49) (mod x 13)
         (< x 52) 10
         ))
 ;;list
 (take (rand-int 12) (repeatedly #(+ 1 (rand-int 52))))))

I would like to use this variable in this function here. This works just fine when I define the variable first then just use its name in the function.

(reduce + (vec (map #(let [x %]
                      (cond
                        (= x 1) 1
                        :else 0
                        ))
                yourHand)))

The issue arrises when I try to define the variable within the function, like this.

(reduce + (vec (map #(let [x %]
                      (cond
                        (= x 1) 1
                        :else 0
                        ))
                (def hand
                  (map
                    ;;fn
                    #(let [x %]
                          (cond
                            ;;hearts
                            (< x 10) (* x -1)
                            (< x 13) -10
                            ;;diamonds
                            (< x 23) (* (mod x 13) -1)
                            (< x 26) -10
                            ;;clubs
                            (< x 36) (mod x 13)
                            (< x 39) 10
                            ;;spades
                            (< x 49) (mod x 13)
                            (< x 52) 10
                            ))
                    ;;list
                    (take (rand-int 12) (repeatedly #(+ 1 (rand-int 52)))))))))

This would not be necessary if not for 2 things. First, I would like to condense this program down to one function if possible (and I think it /is/ possible!). Second, I need to use this variable at another point in my program so I need to be able to reference it somehow.

Anyway, when I try to evaluate the above function, it complains that it doesn't know "how to create ISeq from: clojure.lang.Var". (This is the error: IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Var clojure.lang.RT.seqFrom (RT.java:542)) I'm assuming this means that it doesn't know how to use my variable as a vector... but it seems to use it as a vector just fine when I define my variable outside of the function!

Any advice?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You shouldn't try to def inside of functions. Generally defs are for top-level namespace values; things that won't (normally) change after the namespace is loaded.

Let's refactor the code a bit to get some reusable functions that don't depend on top-level/static namespace values. Instead of (def yourHand ...) we can have a function that generates hands:

(defn deal-hand []
  (map
    ;;fn
    #(cond ;; you have a subtle bug here that sometimes returns nil
       ;;hearts
       (< % 10) (* % -1)
       (< % 13) -10
       ;;diamonds
       (< % 23) (* (mod % 13) -1)
       (< % 26) -10
       ;;clubs
       (< % 36) (mod % 13)
       (< % 39) 10
       ;;spades
       (< % 49) (mod % 13)
       (< % 52) 10)
    ;;list
    (take (rand-int 12) (repeatedly #(inc (rand-int 52))))))

Then if you still wanted a namespace def, you could get it like this:

(def your-hand (deal-hand))

And we can wrap your reduce in another function that takes a hand:

(defn score-hand [hand] ;; I made a few simplifications here, but logic is the same
  (reduce + (mapv #(if (= 1 %) 1 0) hand)))

Now you have two reusable functions that can generate and score hands:

(deal-hand)
=> (-10 -9 -9 -10 -3 7)
(deal-hand)
=> (8 -2 10 -9 1 2 -10 3 nil 5)
(score-hand (deal-hand))
=> 1

If you need to use a hand in other parts of your program, think about how you can structure your functions to take hands as input, and how hands can flow through your program's functions.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...