Why can't I use a partial function or an anonymous function in a chained call with ->?
(->
"123"
seq
sort
reverse
(partial apply str))
=> #<core$partial$fn__4230 clojure.core$partial$fn__4230#335f63af>
I would have thought the partial function would be created and immediately applied to the previous function's result, but it's actually returned itself.
A simple chaining of functions with one parameter of course works without problems:
(->
"123"
seq
sort
reverse
clojure.string/join)
As -> and ->> are just macros, you can test what -> expands to with macroexpand-1 (note the quote ')
user=> (macroexpand-1 '(->
"123"
seq
sort
reverse
(partial apply str)))
(partial (reverse (sort (seq "123"))) apply str)
So that's why you get a function instead of a string - result is partial of collection (which is a function) returned from reverse and apply str as arguments.
If for some reason you need to apply a funcion in ->, you should wrap it in parens:
user=> (macroexpand-1 '(->
"123"
((partial sort)) ; we add parens around so -> have plase to insert
))
((partial sort) "123")
Or you can use ->> macro, as it is doing same work as partial here:
((partial str "hello ") "world")
"hello world"
and
(->> (str "hello ") "world") ; expands to (str "hello " "world")
"hello world"
The -> macro is defined as:
(doc ->)
-------------------------
clojure.core/->
([x & forms])
Macro
Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
second item in second form, etc.
Therefore (apply str) yields an error, because the list from the former function is entered as the second argument:
(->
"123"
seq
sort
reverse
(apply str))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn clojure.core/apply (core.clj:624)
Instead one should use the macro ->>, which applies to the last item:
clojure.core/->>
([x & forms])
Macro
Threads the expr through the forms. Inserts x as the
last item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
last item in second form, etc.
Then the solution with apply looks like this:
(->>
"123"
seq
sort
reverse
(apply str))
=> "321"
UPDATE: expanded version of the -> and ->>:
(macroexpand-1 '(->>
"123"
seq
sort
reverse
(apply str)))
=> (apply str (reverse (sort (seq "123"))))
As you can see from the expanded versions, there's only a difference in how the form (apply str) is interpreted. With -> the second item is inserted while ->> inserts the last item.
(macroexpand-1 '(->
"123"
seq
sort
reverse
(apply str)))
=> (apply (reverse (sort (seq "123"))) str)
Related
I am trying to convert SICP's meta-circular evaluator to Clojure. In setup-environment a call to extend-environment does not compile because I get the error "Attempting to call unbound fn". Here's part of the code:
(... loads of methods for creating and managing environment list)
(def primitive-procedures
(list (list 'car first)
(list 'cdr rest)
(list 'cons conj) ;; TODO: reverse
(list 'null? nil?)
(list 'list list)
(list '+ +)
(list '- -)
(list '* *)
(list '/ /)
;; more primitives
))
(def primitive-procedure-names
#(map [first
primitive-procedures]))
(def primitive-procedure-objects
(fn [] (map (fn [p] (list 'primitive (second p)))
primitive-procedures)))
(def the-empty-environment '())
(defn extend-environment [vars vals base-env]
(if (= (count vars) (count vals))
(conj base-env (make-frame vars vals))
(if (< (count vars) (count vals))
(throw (Throwable. "Too many arguments supplied") vars vals)
(throw (Throwable. "Too few arguments supplied") vars vals))))
;; Added # in front here so it could be called (???)
(defn setup-environment []
#(let [initial-env
(extend-environment (primitive-procedure-names)
(primitive-procedure-objects)
the-empty-environment)] ;; <= that does not work
(define-variable! 'true true initial-env)
(define-variable! 'false false initial-env)
initial-env)))
;; Method for interacting with the evaluator:
(defn driver-loop []
(prompt-for-input input-prompt)
(let [input (read)]
(let [output (m-eval input the-global-environment)]
(announce-output output-prompt)
(user-print output)))
(driver-loop))
(...)
(def the-global-environment (setup-environment))
(driver-loop)
And when I evaluate the extend-environment method I get the following error:
Caused by java.lang.IllegalStateException
Attempting to call unbound fn:
#'scheme-evaluator/extend-environment
Var.java: 43 clojure.lang.Var$Unbound/throwArity
AFn.java: 40 clojure.lang.AFn/invoke
scheme-evaluator.clj: 277 scheme-evaluator/eval7808
I think I am not providing the right type of parameters or I have not created the right type of function. I tried various variations of anonymous methods and passing in parentheses or without, but I don't get it to compile.
Does anyone know what the reason is for this error and how can I fix it?
The definition of
(def primitive-procedure-names
#(map [first
primitive-procedures]))
likely does not do what you intend. As written this defines a function that takes no arguments and returns transducer (which is a function) that will, if applied to a sequence substitute the values 0 and 1 for the functions first and primitive-procedures respectively. I'll demonstrate first with functions and then with values of numbers to make what's happening more clear (hopefully):
user> (into [] (map [first 'example]) [0 1])
[#function[clojure.core/first--4339] example]
user> (into [] (map [1 2]) [0 1])
[1 2]
perhaps you wanted
(def primitive-procedure-names
(map first primitive-procedures))
And may I suggest using the defn form for defining functions and the def form for defining values unless you have a really strong reason not to.
setup-environment is a function that returns a function which will if you call that function return a function that return's the initial-environment unmodified by the calls to define-variable. In Clojure the collection types are immutable so if you want to make several changes to a collection it's necessary to chain the result of adding the first one into the imput of adding the second one, then return the result of adding the second one:
(add-second (add-first initial-value))
which can also be written like this:
(-> initial-value
add-first
add-second)
which is just a shorthand for the example above.
I'm working on problem #74 at 4clojure.com, the solution of mine is as following:
(defn FPS [s]
(->>
(map read-string (re-seq #"[0-9]+" s))
(filter #(= (Math/sqrt %) (Math/floor (Math/sqrt %))))
(interpose ",")
(apply str)))
It works pretty well. But if I use the "thread-first" macro ->
(defn FPS [s]
(->
(map read-string (re-seq #"[0-9]+" s))
(filter #(= (Math/sqrt %) (Math/floor (Math/sqrt %))))
(interpose ",")
(apply str)))
It returns: ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IFn clojure.core/apply (core.clj:617)
Why can "->>" not be replaced by "->" in this problem?
Thread-last macro (->>) inserts each for as the last element of the next form. Thread-first macro (->) inserts it as the second element.
So, this:
(->> a
(b 1)
(c 2))
translates to: (c 2 (b 1 a)), while
(-> a
(b 1)
(c 2))
translates to: (c (b a 1) 2).
In Clojure REPL:
user=> (doc ->)
-------------------------
clojure.core/->
([x & forms])
Macro
Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
user=> (doc ->>)
-------------------------
clojure.core/->>
([x & forms])
Macro
Threads the expr through the forms. Inserts x as the
last item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
last item in second form, etc.
filter function expects the first argument to be a function, not a sequence and by using S-> , you are not satisfying its requirement.
That is why you are getting clojure.lang.LazySeq cannot be cast to clojure.lang.IFn exception in your code.
I have 2 bindings I'm calling path and callback.
What I am trying to do is to return the first non-empty one. In javascript it would look like this:
var final = path || callback || "";
How do I do this in clojure?
I was looking at the "some" function but I can't figure out how to combine the compjure.string/blank check in it. I currently have this as a test, which doesn't work. In this case, it should return nil I think.
(some (clojure.string/blank?) ["1" "2" "3"])
In this case, it should return 2
(some (clojure.string/blank?) ["" "2" "3"])
(first (filter (complement clojure.string/blank?) ["" "a" "b"]))
Edit: As pointed out in the comments, (filter (complement p) ...) can be rewritten as (remove p ...):
(first (remove clojure.string/blank? ["" "a" "b"]))
If you are so lucky to have "empty values" represented by nil and/or false you could use:
(or nil false "2" "3")
Which would return "2".
An equivalent to your JavaScript example would be:
(let [final (or path callback "")]
(println final))
If you want the first non blank string of a sequence you can use something like this:
(first (filter #(not (clojure.string/blank? %)) ["" "2" "3"]))
This will return 2
What i don't understand is your first example using the some function, you said that it should return nil but the first non blank string is "1".
This is how you would use the some function:
(some #(when-not (empty? %) %) ["" "foo" ""])
"foo"
(some #(when-not (empty? %) %) ["bar" "foo" ""])
"bar"
As others have pointed out, filter is another option:
(first (filter #(not (empty? %)) ["" "" "foo"])
"foo"
A third option would be to use recursion:
(defn first-non-empty [& x]
(let [[y & z] x]
(if (not (empty? y))
y
(when z (recur z)))))
(first-non-empty "" "bar" "")
"bar"
(first-non-empty "" "" "foo")
"foo"
(first-non-empty "" "" "")
nil
I used empty? instead of blank? to save on typing, but the only difference should be how whitespace is handled.
It was difficult for me to tell exactly what you wanted, so this is my understanding of what you are trying to do.
In my case, I wanted to find if an item in one report was missing in a second report. A match returned nil, and a non-match returned the actual item that did not match.
The following functions wind up comparing the value of a mapped value with a key.
Using something like find-first is probably what you want to do.
(defn find-first
"This is a helper function that uses filter, a comparision value, and
stops comparing once the first match is found. The actual match
is returned, and nil is returned if comparision value is not matched."
[pred col]
(first (filter pred col)))
(defn str-cmp
"Takes two strings and compares them. Returns 0 if a match; and nil if not."
[str-1 str-2 cmp-start-pos substr-len]
(let [computed-str-len (ret-lowest-str-len str-1 str-2 substr-len)
rc-1 (subs str-1 cmp-start-pos computed-str-len)
rc-2 (subs str-2 cmp-start-pos computed-str-len)]
(if (= 0 (compare rc-1 rc-2))
0
nil)))
(defn cmp-one-val
"Return nil if first key match found,
else the original comparision row is returned.
cmp-row is a single sequence of data from a map. i
cmp-key is the key to extract the comparision value.
cmp-seq-vals contain a sequence derived from
one key in a sequence of maps.
cmp-start and substr-len are start and stop
comparision indicies for str-cmp."
[cmp-row cmp-key cmp-seq-vals cmp-start substr-len]
(if (find-first #(str-cmp (cmp-key cmp-row) %1 cmp-start substr-len) cmp-seq-vals)
nil
cmp-row))
How to understand this simple clojure code?
I kind of understand what it is trying to do but can someone explain the syntax in great detail so I can confidently use it?
(map (fn [x] (.toUpperCase x)) (.split "Dasher Dancer Prancer" " "))
From Clojure REPL:
(doc map)
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
Returns a lazy sequence consisting of the result of applying f to the
set of first items of each coll, followed by applying f to the set
of second items in each coll, until any one of the colls is
exhausted. Any remaining items in other colls are ignored. Function
f should accept number-of-colls arguments.
(.split "Dasher Dancer Prancer" " ") is generating a sequence of strings and each tokenized string will be passed to (fn [x] (.toUpperCase x))
However, (fn [x] (.toUpperCase x)) is too much unnecessary typing. You can do:
(map #(.toUpperCase %) (.split "Dasher Dancer Prancer" " "))
or:
(map (memfn toUpperCase) (.split "Dasher Dancer Prancer" " "))
This is defining a lambda (an anonymous function, which calls toUpperCase on its single argument), and applying it (using map) to each result of String.split().
map takes a function and a sequence of things to apply that function to, and returns a sequence of results from applying the function to the input sequence.
The following breaks the operation down into smaller pieces:
(defn upper-case-fn [^String x]
"this makes the same function, but not anonymous, and provides a type hint
(making it more efficient by avoiding the need for reflection)."
(.toUpperCase x))
;; you could also write the above like so:
(def upper-case-fn (fn [x] (.toUpperCase x)))
(def input-seq
"this assigns your input seq to a var; in the real world, with dynamic data,
you wouldn't do this"
(.split "Dasher Dancer Prancer" " "))
(def output-seq
"this is precisely the same as your sample, except that it's using a named
function rather than an anonymous one, and assigns the output to a var"
(map upper-case-fn input-seq))
;; if you enter this at a repl, you're looking at the contents of this var
output-seq
I'm trying to build a set of functions to compare sentences to one another. So I wrote a function called split-to-sentences that takes an input like this:
"This is a sentence. And so is this. And this one too."
and returns:
["This is a sentence" "And so is this" "And this one too."]
What I am struggling with is how to iterate over this vector and get the items that aren't the current value. I tried nosing around with drop and remove but haven't quite figured it out.
I guess one thing I could do is use first and rest in the loop and conj the previous value to the output of rest.
(remove #{current-value} sentences-vector)
Just use filter:
(filter #(not= current-value %) sentences-vector)
I believe you may want something like this function:
(defn without-each [x]
(map (fn [i] (concat (subvec x 0 i) (subvec x (inc i))))
(range (count x))))
Use it like this:
>>> (def x ["foo" "bar" "baz"])
>>> (without-each x)
==> (("bar" "baz") ("foo" "baz") ("foo" "bar"))
The returned elements are lazily concatenated, which is why they are not vectors. This is desirable, since true vector concatenation (e.g. (into a b)) is O(n).
Because subvec uses sharing with the original sequence this should not use an excessive amount of memory.
The trick is to pass your sentences twice into the reduce function...
(def sentences ["abcd" "efg" "hijk" "lmnop" "qrs" "tuv" "wx" "y&z"])
(reduce
(fn [[prev [curr & foll]] _]
(let [aren't-current-value (concat prev foll)]
(println aren't-current-value) ;use it here
[(conj prev curr) foll]))
[[] sentences]
sentences)
...once to see the following ones, and once to iterate.
You might consider using subvec or pop because both operate very quickly on vectors.