Question

Both of the below functions return the same output, but the first one uses reduce and a pair of quote marks to achieve the same thing. I played with this code and if you delete the "" marks, the first character in the sequence is not converted from it's integer value. The second one seems clear to me, but I feel that the first way is superior, because it packages all of the desired effects into a single function literal. Could somebody unpack the anonymous function for me to explain what variables % and %2 are referring to and tell me why we need the "" only for the first integer (115) in the vector?

 (reduce #(str % (char %2)) ""
            [115 101 99 114 101 116 32 109 101 115 115 97 103 101 115])

 (apply str (map #(char %) [115 101 99 114 101 116 32 109 101 115 115 97 103 101 115]))

The first function was taken from the Clojure Cookbook discussion on int to str conversion, here.

Was it helpful?

Solution

You can find the anonymous function reader macro here

Anonymous function literal (#())

#(...) => (fn [args] (...))

where args are determined by the presence of argument literals taking the form %, %n or %&. % is a synonym for %1, %n designates the nth arg (1-based), and %& designates a rest arg. This is not a replacement for fn - idiomatic used would be for very short one-off mapping/filter fns and the like. #() forms cannot be nested.

% or %1 refers to the first argument and %2 refers to the second.

In your case, in the first approach, % refers to "" and %2 refers to the vector of integers; in the second approach, % to the vector of integers.

As for the difference between reduce and apply here, reduce provides an supplied val, and in your case "". Without this "", reduce would call str with 115 and (char 101), which would produce "115e". Instead of calling str with the first and second element in your vector, you should call str with an empty string and the first element of your vector, which would produce "s". And in the next reduce loop, str would be called with the parameter "s" and 101, yielding "se", and so on.

And for the apply call, you've mapped char to the vector of integer before you call apply, thus the parameter of apply would be: 1. the function str; 2.a vector of characters the function map produced.

Also, you can check out more information about differences between apply and reduce in this question.

OTHER TIPS

reduce takes an optional first value otherwise it grabs the first element from the collection as is and starts reducing the rest of the collection. this would work but changes your collection

(reduce #(str %1 (char %2))
        ["" 101 99 114 101 116 32 109 101 115 115 97 103 101 115])

It is better to map then reduce like so

(reduce str 
  (map (comp str char) 
    [115 101 99 114 101 116 32 109 101 115 115 97 103 101 115]))

or as noisesmith notes below the following is even clearer

(reduce str 
  (map char
    [115 101 99 114 101 116 32 109 101 115 115 97 103 101 115]))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top