Clojure: Is it possible to execute multiple expressions in a `cond' case? - clojure

In clojure, is it possible to execute multiple expressions in a cond case, without do or let form. In Racket, one may do things as:
(cond
(> a 0) ((display a) (display (* a a))
(= a 0) ...
...

Another form that contains an implicit do is when, so “yes,” you could achieve this without do or let:
(cond
(> a 0) (when true
(println a)
(println (* a a))))
But, of course, that's contrived and the real answer to your question is “no.”
Each clause has a pair of forms: A test form and an expression form. You can't have multiple expression forms in a cond clause—you'd need to further wrap them in a single form such as do. They are referred to as expression forms because usually their value is of interest (in a purely functional context) because it is the value of the expression in the clause with the first truthy test that the entire cond form evaluates to.
But, if you are using cond as a way to achieve conditional side effects, perhaps do is a good reinforcement of the intent:
(cond
(> a 0) (do (println a)
(println (* a a))))

Related

how to get a list out of list of lists in common lisp

I am new to common lisp and trying to get a list out of a splitted string.
For example:
["4-No 16dia","6-No 20dia"]
Now I want to collect only the third element like ["16","20"]
I have got the splitting part correctly using:
(defun my-split (string &key (delimiterp #'delimiterp)
)
(loop :for beg = (position-if-not delimiterp string)
:then (position-if-not delimiterp string :start (1+ end)
)
:for end = (and beg (position-if delimiterp string :start beg))
:when beg :collect (subseq string beg end)
:while end))
where :
(defun delimiterp (c) (position c " ,-:"))
but collecting only the third element into a list is the tricky part , I have tried:
(defparameter *list1*
(loop for i in (cdr list)
(append (parse-integer
(nth 0
(my-split (nth 3 i)
:delimiterp #'delimiterp))))))
P.S: there are two list cz the example string is itself part of a list-of lists
Please help me, thanks in advance
I would use a regular expression, and I think I would do this largely irrespective of the language that I was using. Of course, some languages don't have regular expressions, but when they do it saves reinventing the wheel.
In Common Lisp, the regular expressions library is called Common Lisp - Practical Perl Compatible Regular Expressions, cl-ppcre. We load this with (ql:quickload "cl-ppcre").
Then the numbers can be returned using (ppcre:scan-to-strings "^(\\d*)-No (\\d*)dia$" x). The regular expression uses \d to pick out a digit, which in Lisp strings is written \\d. The asterisk says return zero or more digits. The parentheses in the regular expression is the bits that we are going to return, the numbers.
Doing this for a list of string is then just using mapcar.
(defparameter text-match "")
(defparameter text-numbers "")
(defparameter test-text '("4-No 16dia" "6-No 23dia"))
(defun extract-numbers (text)
(setf (values text-match text-numbers)
(ppcre:scan-to-strings "^(\\d*)-No (\\d*)dia$" text))
text-numbers)
(defun extract-numbers-from-list (lst)
(mapcar #'extract-numbers lst))
(extract-numbers-from-list test-text) ; => (#("4" "16") #("6" "23"))
Edit: lexical bindings
When I was writing the above, I was trying to get the regular expression right AND trying to get the lexical bindings right at the same time. Having only limited time I put the effort into getting the regular expressions right, and used dynamic variables and setf. OK, it got the job done, but we can do better.
The classical lexical binding system is let, syntax (let ( (var1 val1) (var2 val2) ...) body). We can try (let ((x 0))), which is valid Lisp code, but which doesn't do much. As soon as the lexical scope ends, the variable x is unbound. Attempting to access x causes an error.
We can return multiple values from many functions, such as floor or scan-to-string. We now have to bind these values to variables, using (multiple-value-bind (variable-list) values). Most websites don't really do a good job of explaining this. Having bound the variables, I was getting errors about unbound variables. OK, it's worth just saying -
multiple-value-bind binds variables lexically, just like let.
The full syntax is (multiple-value-bind (variable-list) values body) and your code goes into the body section, just like let. Hence the above code becomes:
(defparameter test-text '("4-No 16dia" "6-No 23dia"))
(defun extract-numbers (text)
(multiple-value-bind (text-match text-numbers)
(ppcre:scan-to-strings "^(\\d*)-No (\\d*)dia$" text)
text-numbers))
(defun extract-numbers-from-list (lst)
(mapcar #'extract-numbers lst))
(extract-numbers-from-list test-text) ; => (#("4" "16") #("6" "23"))
Just to add, cl-ppcre also has register-groups-bind to do regex matching, binding, and converting in a single form:
CL-USER> (cl-ppcre:register-groups-bind ((#'parse-integer no dia))
("(\\d+)-No (\\d+)dia" "4-No 16dia")
(values no dia))
4
16
Without dependencies, one could use:
(defun extract-nums (s)
(mapcar #'(lambda (x) (parse-integer x :junk-allowed t))
(ql-util:split-spaces s)))
And try it with:
(defparameter *s* (list "4-No 16dia" "6-No 20dia"))
(mapcar #'extract-nums *s*)
;; => ((4 16) (6 20))
parse-integer with the setting junk-allowed-p t helps with extracting integer numbers from the string a lot.
But yes, in real-life I would also just use cl-ppcre, e.g.
Mainly the functions cl-ppcre:split and cl-ppcre:scan-to-strings.
(ql:quickload :cl-ppcre)
(defun extract-nums (s)
(mapcar #'parse-integer (cl-ppcre:scan-to-strings "(\\d+)-No (\\d+)dia" s))
And from then on it is just
(second (map #'list (mapcar #'extract-nums *s*))
;; => (16 20)

Clojure: pass value if it passes predicate truth test

Is it possible to remove the let statement / avoid the intermediate 'x' in the following code?:
(let [x (f a)]
(when (pred? x) x))
I bumped into this problem in the following use case:
(let [coll (get-collection-somewhere)]
(when (every? some? coll) ; if the collection doesn't contain nil values
(remove true? coll))) ; remove all true values
So if the collection is free of nil values, only not-true values remain, like numbers, strings, or whatever.
So, I'm looking for something like this:
(defn pass-if-true [x pred?]
(when (pred? x) x))
Assuming that you don't want to define that pass-if-true function, the best you can do is an anonymous function:
(#(when (every? some? %)
(remove true? %))
(get-collection-somewhere))
You could also extract the predicate and transformation into parameters:
(#(when (%1 %3) (%2 %3))
(partial every? some?)
(partial remove true?)
(get-collection-somewhere))
The let form is necessary to prevent your collection-building function from running twice:
(f a) or (get-collection-somewhere)
This is a typical idiom and you are doing it correctly.
Of course, you don't need the let if you already have the collection and are not building inside this expression.
However, you may wish to see when-let:
https://clojuredocs.org/clojure.core/when-let
It can save some keystrokes in some circumstances, but this isn't one of them.

I'm having a hard time understanding the stabbing -> Clojure shorthand

In Clojure, what does (-> ... ... ...) means? Changing the order of things results a different output.
(defn my-method
"description"
[& args]
(-> things/thing1
things/thing2
things/thing3
things/thing4
things/thing5))
This is "thread-first" macro:
(-> a b c)
is equivalent to
(c (b a))
Basically this macro is used to avoid nesting big amount of forms. It just inserts first form as first argument of second form: (-> a b) becomes (b a). Then resulting form is inserted as first argument of third form: (-> (b a) c) becomes (c (b a)). So, your example is equivalent to:
(defn my-method
"description"
[& args]
(things/thing5 (things/thing4 (things/thing3 (things/thing2 things/thing1)))))
(doc) is a convenient utility that is running in a Clojure REPL. It should be at the corner of everyday's development.
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
second item in second form, etc.

clojure / lisp dialect etc function result expression

Are you able to have multiple expressions in a clojure function.
Below is an example.
(defn side-effect-add [a b]
(println "Doing some side effect")
(+ 1 2)
(+ a b)
)
Is something like this ok or is a function allowed to have / return the result of a single expression in the body.
Thanks.
This is valid Clojure.
Of a sequence of expressions/forms , the function returns the value
of the last. Any others only have side-effects, such as (println ...) above.
A function body has an implicit do to bring this about.

Destructuring: How can this even work?

As an answer to a question on SO I was building a recurring function, and built my most complicated destructuring yet, which miraculously worked:
(defn fib?
[a b & [c & r]]
(if (= c (+ a b))
(if r
(recur b c r)
true)
false))
(fib? 0 1 1)
=> true
(fib? 2 3 5 8 13)
=> true
But I have no idea why it should work. The r used in therecur is a collection, something which would make the original function fail.
(fib? 2 3 [5 8 13])
=> false
I wanted to use something like apply recur there, but since recur is a special form, that's not possible. So I tried without it and it worked. Does recur have magical auto-apply properties or is there something else I'm not seeing.
The are two parts to the answer:
The "rest" parameter of a variadic function becomes the final parameter in any recur forms that recur to the top of the function. At this point it is no longer special in any way. You'll normally want to ensure that any values passed in that position actually are sequential, but even this is not enforced.1
Destructuring is just syntactic sugar provided by the fn and let macros. The desugared version of an fn form that uses destructuring in its parameter vector takes a certain number of regular arguments, then destructures them in a let form wrapping the entire body. Thus if you recur to the top of a function that uses destructuring in its parameter vector, the new values will be destructured for the next iteration.
1 For example, ((fn [& xs] (if (seq? xs) (recur (first xs)) xs)) 1 2 3) returns 1.