Clojure cats append nil behaviour - clojure

I am using funcool/cats, append monoid with the following code :
(m/mappend (maybe/just [1 2 3])
nil
(maybe/just [4 5 6])
(maybe/nothing)) ;;=> #<Just [1 2 3 4 5 6]>
What is the rationale for treating nil as maybe/nothing ?
Note : the version is [funcool/cats "1.2.1"]

From the commit log, it seems like it's
just for (sic) avoid accidental null pointer exceptions
This is also documented here: http://funcool.github.io/cats/latest/#nil
Given the fact that nil is both a value and a type, we have extended
the nil type to be equivalent to Maybe monad’s Nothing.

Related

Clojure - how exactly symbols are evaluated? [duplicate]

This question already has an answer here:
What do Clojure symbols do when used as functions?
(1 answer)
Closed 5 years ago.
We know clojure evaluates (+ 1 1) in couple of stages from reading the unicode characters to actual evaluation of the reader output...
In code, that looks something like (eval (read-string "(+ 1 1)"))
However it hurts my brain when ('+ '1 '2) (or ('+ 1 2)) gives me 2....
core> (def something ('+ '1 '2))
#'alcamii4hr.core/something
core> (type something)
java.lang.Long
Symbols, like keywords, can be invoked like functions. When invoked, they both do the same thing, look themselves up in what they presume to be a map. They have two arities [a-map] and [a-map not-found].
;; not-found defaults to nil
('foo {'bar 42}) ;=> nil
('foo {'foo 42}) ;=> 42
;; not-found can also be supplied in the arity-2 case
('foo {'bar 42} :not-found) ;=> :not-found
In your specific case, it just assumes that the first argument is something associative, and doesn't check. It can't find the symbol + in what it presumes to be a map, so it returns the not-found value: 2.
('+ '1) ;=> nil ; not-found
('+ '1 '2) ;=> 2 ; because 2 is the not-found values
('+ '1 '2 '3) ;=> clojure.lang.ArityException
To see how this all fits together, you can check the invoke method on the symbol class,
which calls clojure.RT.get, which is what looks something up in an associative thing. This is the same method called by clojure.core/get.
In clourescript, this works the same way, but is implemented differently. (In clojurescript itself, and not in the host language.) You can read about that here.

why does clojure's map println only works in repl?

I use lein new app test-println to create a clojure app and launch the repl with lein repl, then I enter (map println [1 2 3 4 5 6]) and get the expected result:
test-println.core=> (map println [1 2 3 4 5 6])
1
2
3
4
5
6
(nil nil nil nil nil nil)
However if I add (map println [1 2 3 4 5 6]) to the end of src/test_println/core.clj:
(ns test-println.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!")
(map println [1 2 3 4 5 6]))
lean run prints only Hello, World!.
map is lazy. To quote the first sentence of the documentation (emphasis added):
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.
The REPL forces evaluation of the expression to show the result, but nothing in your code does. dorun would solve this, but you probably should look at doseq / doall instead.
If your goal is to run a single procedure over every item in a single collection, you should use run!:
(run! println [1 2 3 4 5 6])
;; 1
;; 2
;; 3
;; 4
;; 5
;; 6
;;=> nil
In cases where the action you need to perform on each collection is more complex than simply applying an existing function, doseq may be more convenient, but run! is a better choice here.

Clojure assoc vector behaviour

Clojure assoc applied to vector seems have inconsistent behaviour
When index is present in vector, assoc replace the value
(assoc [1 2 3 4 5] 3 42) => [1 2 3 42 5]
When index is next to last one, the vector grows (conj equivalent)
(assoc [1 2 3 4 5] 5 42) => [1 2 3 4 5 42])
Otherwise IndexOutOfBoundsExcpetion is thrown
though it useful in some cases like reduce assoc, this may lead to subtle bugs in a program
Is it expected behaviour or probably bug in assoc for vector?
It is expected. See the docstring for assoc, especially the last note regarding the index argument.
This is described at the top of p. 101 of Clojure Programming.

How to determine the meaning of nil in clojure?

for example,
> (some #{nil} #{nil 1 2 3})
nil
> (some #{} #{nil 1 2 3})
nil
I know I could use
(some nil? #{nil 1 2 3})
to check nil value. I can't think of any good example at the moment.
But generally, when nil is returned, how do I determine if nil means nothing is found or the value nil is found?
nil is just a value, and its meaning depends on context.
It's just like all other values in that regard: the only thing to be aware of is that it is falsy, i.e. counts as false in conditional expressions.
Three particular cases to be aware of:
nil is the return value used to indicate an empty sequence, e.g. in (seq [])
nil is often used as a return value to indicate false, e.g. in (or false nil)
nil is returned by default when a map lookup can't find a given key, e.g. in ({:a 1} :b)
These cases can on occasion cause ambiguity: if so then you need to use a different function. Your example is a good one:
(some #{nil} #{1 2 3}) => nil (failure - no result found)
(some #{nil} #{nil 1 2 3}) => nil (success - nil result found!!!)
In this case you've simply chosen the wrong function: you can't use the set #{nil} to detect nils.... instead you can just use nil? or you could even do something fancy with an alternative return value like #(get #{nil} % :not-found)
Isn't this a question of the question you're asking, rather than anything particular to Clojure ?
You could ask:
> (filter nil? #{nil 1 2 3})
> (nil)
which tells you there was one nil in the set; you get what you ask for - you asked an ambiguous question and got a suitably ambiguous response.

In Clojure, how would I map everything to a constant value?

For example
(map #(+ 10 %1) [ 1 3 5 7 ])
Will add 10 to everything
Suppose I want to map everything to the constant 1. I have tried
(map #(1) [ 1 3 5 7 ])
But I don't understand the compiler error.
(map #(1) [ 1 3 5 7 ])
Won't work for two reasons:
#(1) is a zero-argument anonymous function, so it won't work with map (which requires a one-argument function when used with one input sequence).
Even if it had the right arity, it wouldn't work because it is trying to call the constant 1 as a function like (1) - try (#(1)) for example if you want to see this error.
Here are some alternatives that will work:
; use an anonymous function with one (ignored) argument
(map (fn [_] 1) [1 3 5 7])
; a hack with do that ignores the % argument
(map #(do % 1) [1 3 5 7])
; use a for list comprehension instead
(for [x [1 3 5 7]] 1)
; use constantly from clojure.core
(map (constantly 1) [1 3 5 7])
Of the above, I think the versions using constantly or for should be preferred - these are clearer and more idiomatic.
The anonymous function #(+ 10 %1) is equivalent to:
(fn [%1]
(+ 10 %1))
Whereas #(1) is equivalent to:
(fn []
(1))
And trying to call 1 as a function with no args just won't work.
I got this from clojure.org
by googling the words "clojure constant function" as I am just beginning to look at clojure
(map (constantly 9) [1 2 3])
cheers