I've put together a higher order function that in certain cases calls a function parameter, but it seems to have different effects depending on the function. I was able to reproduce the same behaviour just with a simple function:
(defn foo [f a b] (f a b))
For "normal" functions it works fine:
user=> (foo list 2 3)
(2 3)
user=> (foo cons 1 '(2 3))
(1 2 3)
user=> (foo println 2 3)
2 3
nil
But for operators, it does not, it just seems to return the last element:
user=> (foo '+ 2 3)
3
user=> (foo '* 2 3)
3
user=> (foo '- 2 3)
3
Why is this the case?
user=> (foo '+ 2 3)
3
Why is this the case?
' (or quote) is creating a symbol of + when you want the + function value itself: https://clojure.org/guides/weird_characters#_quote
(quote foo) => foo ;; symbol
'foo => foo ;; symbol
So the behavior of always returning the second argument comes from the fact that symbols (like keywords) also act as functions, typically used as a shorthand for get on associative structures (like maps), so these are functionally equivalent:
('foo 1 2) => 2
(get 1 'foo 2) => 2
The 2 happens to be in the position used for default values when the key isn't found in the associative structure.
This would be useful if you had a map with symbol keys, just like keywords:
('foo {'foo 1}) => 1
({'foo 1} 'foo) => 1
('foo {'bar 1} 2) => 2
In clojure, "operators" like + are just normal functions. Don't use the single-quote and it'll work fine.
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn foo [f a b] (f a b))
(dotest
(spyx (foo list 2 3))
(spyx (foo println 2 3))
(spyx (foo + 2 3))
(spyx (foo * 2 3))
(spyx (foo - 2 3)) )
with results:
(foo list 2 3) => (2 3)
2 3 ; result of (println 2 3)
(foo println 2 3) => nil ; println always returns `nil`
(foo + 2 3) => 5
(foo * 2 3) => 6
(foo - 2 3) => -1
The helper function spyx just prints an expression, then its value.
Related
I am just started clojure but I can't seem to figure out using/creating higher order functions.
I have partitioned a collection and I want to pass that into another function that will do something to the window of items. I am not sure how to go about doing this.
(def foo [:a :b :c :d :e])
(partition 3 1 foo)
;;=> ((:a :b :c) (:b :c :d) (:c :d :e))
(defn bar [start next end])
I think the basic outline would be.
(defn faz [collect]
(partition 3 1 collect)
;;maybe do here before passing
(bar stand next end)
)
I might be getting ahead of myself but I also see there are other functions like reduce and apply they can do something similar right? Although, most examples I see have it so they perform operations on two items at a time which are similar to (partition 2 1 foo)
You can do something like
(defn bar [start next end])
(defn faz [collect]
(let [partitions (partition 3 1 collect)]
(apply bar partitions)
))
or if you want to call bar directly, you can use destructuring
(defn bar [start next end])
(defn faz [collect]
(let [partitions (partition 3 1 collect)
[start next end] partitions]
(bar start next end)
))
Your question is general and there is more ways to achieve this, based on expected result and used function.
If you want to return sequence of results, use map and apply:
(defn results-for-triplets [collect]
(map #(apply + %) (partition 3 1 collect)))
(results-for-triplets [1 2 3 4 5])
=> (6 9 12)
For better readability, you can use ->> macro.
(defn results-for-triplets [collect]
(->> collect
(partition 3 1)
(map #(apply + %))))
(results-for-triplets [1 2 3 4 5])
=> (6 9 12)
You can avoid apply, if your function destructures passed sequence:
(defn sum3 [[a b c]]
(+ a b c))
(defn results-for-triplets [collect]
(->> collect
(partition 3 1)
(map sum3)))
(results-for-triplets [1 2 3 4 5])
=> (6 9 12)
If you want to call function for side effect and then return nil, use run!:
(defn print3 [[a b c]]
(println a b c))
(defn results-for-triplets [collect]
(->> collect
(partition 3 1)
(run! print3)))
(results-for-triplets [1 2 3 4 5])
1 2 3
2 3 4
3 4 5
=> nil
Playing around with Clojure, I noticed that ('+ 2 2) didn't throw an error like I would've expected--it returns 2. I've spent a few minutes playing around:
(def f (cast clojure.lang.IFn 'a-symbol))
(f 5) ;; => nil
(f 5 5) ;; => 5
(f 5 5 5) ;; ArityException Wrong number of args (3) passed to: Symbol
(f "hey") ;; => nil
(f "foo" "bar") ;; => "bar"
(f "foo" "bar" "baz") ;; => ArityException Wrong number of args (3) passed to: Symbol
As far as I can tell, symbols are being cast to some function with the name Symbol, that takes two arguments and returns the second one. I'm guessing it has something to do with the implementation of the symbol class?
When called as a function symbols (like keywords) look them selves up in the map passed as the second argument
user> (def my-map '{a 1 b 2 c 3})
#'user/my-map
user> ('a my-map)
1
user> ('a my-map :not-found)
1
user> ('z my-map :not-found)
:not-found
and return the third argument, if it was passed, to indicate when nothing was found. In your example when you look up a symbol in something that is not a map, for instance the number 5, it doesn't find it:
user> ('z 4 :not-found)
:not-found
user> ('z 'z :not-found)
:not-found
And returns the third argument, or nil if no third argument was passed.
I'm running through some of the 4Clojure problems and hit some weird behavior with some of my code. Upon further investigation it seems the culprit was using the quote macro vs list function. Why does this matter in the code below, and why does it produce the incorrect result?
user=> (= (class '(/ 1 2)) (class (list / 1 2)))
true
user=> (def a '(/ 1 2))
#'user/a
user=> (def b (list / 1 2))
#'user/b
user=> (class a)
clojure.lang.PersistentList
user=> (class b)
clojure.lang.PersistentList
user=> (apply (first a) (rest a))
2
user=> (apply (first b) (rest b))
1/2
user=> (class (first a))
clojure.lang.Symbol
user=> (class (first b))
clojure.core$_SLASH_
'(/ 1 2)
is analogous to:
(list '/ 1 2)
When you don't quote /, you get its value, which is the built-in division function, rather than the symbol.
Unfortunately, you have used the symbol object as function in expression (apply (first a) (rest a)). The symbol object looks for the value of itself as a key in a map:
('/ {'+ :plus '/ :slash '- :minus} :not-found)
=> :slash
('/ {'+ :plus '$ :dollar '- :minus} :not-found)
=> :not-found
('/ 1 :not-found)
=> :not-found
('/ 1 2)
=> 2
The question is about not=:
Clojure> (doc not=)
---------------------
Cloure.core/not=
([x] [x y] [x y & more])
Same as (not (= obj1 obj2))
Clojure> (not= [1 2 3] [1 2 3])
false
Clojure> (not= '(1 2 3) '(1 2 3))
false
Clojure> (not= #(1 2 3) #(1 2 3))
true
Any suggestion is appreciated!
Sets use braces
user=> (not= #(1 2 3) #(1 2 3))
true
user=> (not= #{1 2 3} #{1 2 3})
false
just for reference the # character is the "dispatch macro" in the clojure reader.
it tells the reader to treat the expression folowing it specially. So far as I know it is
the only reader macro defined in clojure.
#( ) define a function. short for (fn [< optional-args >] ...)
#" " define a regular expression
#' reference a var it's self instead of the value in a var.
#{ } define a set.
#_ don't read the next statement. this is like a super comment, it is more through than a comment but the distinction is not commonly used.
Others have commented that #(1 2 3) is not a set, but rather a function (that raises an error when invoked). The reason that #(1 2 3) is not equal to #(1 2 3) is that each invocation of #(...) creates a new anonymous function, and each new function belongs to a new Java class:
user=> (class #(1 2 3))
user$eval60$fn__61
user=> (class #(1 2 3))
user$eval64$fn__65
These classes have an equals method that doesn't consider objects of the other classes equal, even though they happen to have been defined in the same way. The method is in fact inherited from java.lang.Object:
user=> (for [m (.getMethods (class #(1 2 3)))
:when (= (.getName m) "equals")]
(.getDeclaringClass m))
(java.lang.Object)
With closure
(apply str [\a \b])
and
(apply str '(\a \b))
returns "ab".
(apply str (\a \b))
returns an error.
Why is that?
Because (\a \b) means "call the function \a with an argument of \b", and since the character \a is not a function, it fails. Note the difference in the following:
user=> (+ 1 2 3)
6
user=> '(+ 1 2 3)
(+ 1 2 3)
As a general rule, if you want to write a literal sequence, use a vector instead of a quoted list since the quote will also stop evaluation of the parts inside the list, e.g.:
user=> [(+ 1 2) (+ 3 4)]
[3 7]
user=> '((+ 1 2) (+ 3 4))
((+ 1 2) (+ 3 4))