Вопрос

if I had an unknown number of argument that I want to bind to each other with a "let", like:

let [a "hello" b 55 ]

If I bind let inside a function/macro or similar and I want to loop though the list, how would I do this?

Note that in the let there are 4 elements but I only want to loop through the "keys". An example of use could be to check if the value bound to a key is a number like b, which is 55

Edit: As an example: Note that this following is very broken but it's merely intended to explain the problem:

(defn func [& arguments] 
 (let [ ~arguments] ((println "omg no way!") (for [x let-list] (number? x (println "roar") )))

input: (func [a "hello" b 55]

So basically: I want to have a function that:

  • binds the arguments to some form of list like: [a b]
  • prints "omg no way!") - should not be part of a loop, should only print once in the function
  • some kind of loop like a for loop that loops through the "let-list" so it would go: "a, is a number? no, is b number? yes, print "roar"

Output: omg no way roar

Once again: I am wondering if there is a way to gain access to the keywords inside the let inside the function. As the for loop shows, I want to access each individual element and do things with the element. Had I used (for [x arguments] instead, it would've given: omg no way, roar roar (because b is tied to 55 so it's a number but 55 is also a number but there's no need to use 55 because 55 is already tied to b)

Это было полезно?

Решение

here is an example of a macro that takes a list of alternating names and values, binds them in a let and then saves a map of the bindings that it just created by introducing a symbol called 'locals' that names a map of local-names to local-values.

(defmacro anaphoric-let [alternating-symbols-and-values & body]
  `(let [~@alternating-symbols-and-values
         names# (quote ~(flatten (partition 1 2 alternating-symbols-and-values)))
         values#  ~(vec (flatten (partition 1 2 alternating-symbols-and-values)))
         ~'locals (zipmap names# values#)]
     ~@body))

any expressions called withing anaphoric-let will be able to use the values form the locals name.

user> (anaphoric-let [a 1 b 2 c 3 d 4] [a locals])
[1 {d 4, c 3, b 2, a 1}]

saving the values in a map after defining them with let and before the body is important to prevent multiple execution and the other sins of unhygienic macros.

this map can then be used to make decisions based on the locals:

user> (anaphoric-let [a 1 b 2 c 3 d 4 e "cat"] 
        (map (fn [[local val]] 
               (str local " is " (if (number? val) val "woof"))) 
              locals))
("e is woof" "d is 4" "c is 3" "b is 2" "a is 1")

or:

user> (anaphoric-let [a 1 b 2 c 3 d 4 e "cat"] 
        (println "omg no way!") 
        (dorun (for [x (vals locals)] 
                 (if (number? x) (println "roar")))))
omg no way!                                                                                                                                                    
roar                                                                                                                                                           
roar                                                                                                                                                           
roar                                                                                                                                                           
roar                                                                                                                                                           
nil

ps: anaphoic macros are any macro that introduces a name into the code it creates that did not exist in the code passed to it.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top