Conditionals in Elisp's cl-loop facility - loops

I'm trying to wrap my head around Elisp's cl-loop facility but can't seem to find a way to skip elements. Here's an artificial example to illustrate the problem: I'd like to loop over a list of integers and get a new list in which all odd integers from the original list are squared. The even integers should be omitted.
According to the documentation of cl-loop, I should be able to do this:
(loop for i in '(1 2 3)
if (evenp i)
append (list)
else
for x = (* x x)
and append (list x))
The desired output is '(1 9) instead I get an error:
cl--parse-loop-clause: Expected a `for' preposition, found (list x)
Apparently the and doesn't work as expected but I don't understand why. (I'm aware that I could simplify the else block to consist of only one clause such that the and isn't needed anymore. However, I'm interested in situations where you really have to connect several clauses with and.)
Second part of the question: Ideally, I would be able to write this:
(loop for i in '(1 2 3)
if (evenp i)
continue
for x = (* x x)
append (list x))
Continue is a very common way to skip iterations in other languages. Why doesn't cl-loop have a continue operator? Is there a simple way to skip elements that I overlooked (simpler than what I tried in the first example)?

In Common Lisp it is not possible to write such a LOOP. See the LOOP Syntax.
There is a set of variable clauses on the top. But you can't use one like FOR later in the main clause. So in an IF clause you can't use FOR. If you want to introduce a local variable, then you need to introduce it at the top as a WITH clause and set it later in the body.
(loop for i in '(1 2 3)
with x
if (evenp i)
append (list)
else
do (setf x (* i i))
and append (list x))
LOOP in Common Lisp also has no continue feature. One would use a conditional clause.
Note, that Common Lisp has a more advanced iteration construct as a library ITERATE. It does not exist for Emacs Lisp, though.

You could do:
(loop for i in '(1 2 3)
if (oddp i) collect (* i i))
That would solve your sample problem.

And here's another without loop (yes, I know you asked for loop):
(let ((ns ()))
(dolist (n '(1 2 3))
(when (oddp n) (push (* n n) ns)))
(nreverse ns))
And without even cl-lib (which defines oddp):
(let ((ns ()))
(dolist (n '(1 2 3))
(unless (zerop (mod n 2)) (push (* n n) ns)))
(nreverse ns))
Everything about such definitions is clear -- just Lisp. Same with #abo-abo's examples.
loop is a separate language. Its purpose is to express common iteration scenarios, and for that it can do a good job. But Lisp it is not. ;-) It is a domain-specific language for expressing iteration. And it lets you make use of Lisp sexps, fortunately.
(Think of the Unix find command -- similar. It's very handy, but it's another language unto itself.)
[No flames, please. Yes, I know that dolist and all the rest are essentially no different from loop -- neither more nor less Lisp. But they are lispier than loop. Almost anything is lispier than loop.]

Here's a loop solution:
(loop for i in '(1 2 3)
when (oddp i) collect (* i i))
Here's a functional solution:
(delq nil
(mapcar (lambda(x) (and (oddp x) (* x x)))
'(1 2 3)))
Here's a slightly different solution (be careful with mapcan - it's destructive):
(mapcan (lambda(x) (and (oddp x) (list (* x x))))
'(1 2 3))

Related

What is the closest equivalent to a for-loop in Racket-sdp?

Is recursion the only way to write something like a for-loop in the Racket dialect sdp ("Schreibe dein Programm!"), in which "(for)" isn't a thing or is there a more "efficient" or simpler way to do so?
What would the closest equivalent to the C++ loop for(i = 0 , i < 100, i++) look like in Racket-sdp code?
How I did this up until now was:
(: my-loop (natural -> %a))
(define my-loop
(lambda (i)
(cond
[(< i 100) (my-loop (+ i 1))] ; <-- count up by one till 99 is reached
[else "done"] ; <-- end
)))
(my-loop 0)
EDIT:
It's more of a general question. If I were to write lets say a raket library which contains a general function, that might be used like this:
(for 0 (< i 100) (+ i 1) (func i))
in my programs which is a for-loop that runs with a given function as it's "body", would there be a way to implement this properly?
[Professor of the mentioned course here.]
Recursion indeed is the only way to express iterated computation in the Racket dialect we are pursuing. (Yes, that's by design.)
Still, higher-order functions (and recursion) provide all you need to create your own "loop-like control structures". Take the following HOF, for example, which models a repeat-until loop:
(: until ((%a -> boolean) (%a -> %a) %a -> %a))
(define until
(lambda (done? f x)
(if (done? x)
x
(until done? f (f x)))))
Note that the until function is tail-recursive. You can expect it to indeed behave like a loop at runtime — a clever compiler will even translate such a function using plain jump instructions. (We'll discuss the above in the upcoming Chapter 12.)
You can make a high-order for-loop.
Here is an simple example:
(define (for start end f)
(define (loop i)
(when (< i end)
(f i)
(loop (+ i 1))))
(loop start))
(for 0 10 (λ (i) (displayln i)))
You can make this more general if you use a next function instead of (+ i 1) and use a while-predicate? function instead of (< i end).

Making a recursive call from the loop macro

I'm pretty new to common lisp and I've been stuck on a particular problem. The function I'm suppose to write takes in two parameters: a function and a List. It iterates through the list and calls the given function on each element in the list. If the function returns true then the element is added to a sub list that is returned
What I've tried so far is:
(defun myFunc(f l)
(loop for x in l
if (listp x) do (myFunc f x)
else if (eql t (funcall f x))
collect x
)
)
The function I've been given for f takes a parameter and if it's is an number, returns true. So far my code works if aList is a simple list such as (1 2 3). However when I input a nested list like (1 2 (4 5) 7) only (1 2 7) is outputted rather than (1 2 (4 5) 7).
I'm assuming it has something to do with my recursive call and what is returning. Would really appreciate some help on this
There are a couple of minor issues. First off, I assume it's just a typo, but you need to replace aFunc with f (as there's no variable aFunc in your code).
Now to the main point of the question. In your else if branch, you correctly collect the value when the predicate is true. But in your recursive case, you simply run some code and discard the result. You're going to want to collect there too.
(defun myFunc (f l)
(loop for x in l
if (listp x)
collect (myFunc f x)
else if (eql t (funcall f x))
collect x))
Finally, just a style note. It's generally more idiomatic to treat a predicate as true if it returns anything truthy, not just t. So if I was writing this, I'd probably replace (eql t (funcall f x)) with simply (funcall f x). If this is a homework assignment and the teacher told you to do it the other way, stick with that. But if it's for your benefit, you may consider changing that as well.

*= operation in Common Lisp

I wonder if there is some function/macro in Common Lisp has similar function as *= or /= operation in C/C++.
incf and decf in Common Lisp can be considered as += and -=.
In C/C++
A *= 2;
equals to
A = A * 2;
In Common Lisp
When I want to set a new value to an array element, I have to write as
(setf (aref arr i) (* (aref arr i) 2))
The statement of accessing the array has to write two times, if there is a function/macro mulf have similar function as *= in C language.
I can write code as
(mulf (aref arr i) 2)
Then the array accessing statement is needed to write only once.
Thanks.
As stated in the comments, this can easily be created using DEFINE-MODIFY-MACRO.
(define-modify-macro mulf (x) *)
Not in the standard either, but it seems the zap macro is here for that. For example:
(zap #'+ x 5)
Here is the suggested implemantion:
(defmacro zap (fn place &rest args)
(multiple-value-bind
(temps exprs stores store-expr access-expr)
(get-setf-expansion place)
`(let* (,#(mapcar #'list temps exprs)
(,(car stores)
(funcall ,fn ,access-expr ,#args)))
,store-expr)))

elisp: syntax error on do clause

I am writing a Greatest Common Factor function.
I kept getting errors saying
"(if t (set q).....)" is not valid syntax
and so I commented it out. But then I was told that my do syntax is invalid.
syntax error on the 'do' clause
But I'm looking at it and seeing no errors. Why will my code not work?
(defun myGCD (a b)
"My function, which returns the Greatest Common Factor"
(let ((x a) (y b) (z 0))
(loop until (or (zerop x) (zerop y))
do ( ;(progn
;(if t ;(< a b)
; If case
;((setq b (- b a)) (setq c a))
; Else case
;((setq a (- a b)) (setq c b))
;)
;(return c)
);)
)
)
)
(myGCD 10 20)
You have basic syntax errors in your code.
In a LOOP form you need to have one or more compound forms after a DO.
(loop ... do () )
is not allowed, because () is not a compound form.
Also note that parentheses are not grouping expressions in a sequence.
((foo 1) (bar 2))
above is not valid Lisp. In Scheme it might be correct, but there the first form then needs to return a function.
To group expressions you would need something like progn, which allows embedded forms and returns the values of the last one:
(progn
(foo 4)
(bar 2))
Above is valid.
As it turns out, you can't have an empty 'do' command. This doesn't explain why the other logic was failing, but I will look at that some more.

How to compare two lists in lisp that are not exactly the same in length or structure?

I have these two lists:
'(and 1 (or a b))
'( (a 0)(b 1) )
I am new to lisp, and I am finding it very hard to figure out how to compare these two lists. I am thinking of creating a comparison function, but I don't know how to compare them one by one as in lisp values aren't returned until the expression is evaluated. Since they aren't the same structure either, I can't assume they will be the same, structurally at least. Any explanation how this works?
Edit: Sorry, I forgot to say why I am comparing. The second list is to suppose to bind the number to everywhere where those variables exists in the first list. So the resulting first list should be:
'(and 1(or 0 1))
Built in:
$ clisp -q
[1]> (sublis '((a . 0) (b . 1)) '(and 1 (or a b)))
(AND 1 (OR 0 1))
[2]>
So the homework reduces to making a wrapper for SUBLIS which accepts the bindings in the form ((a 0) (b 1)) rather than ((a . 0) (b . 1)).
Clue:
(loop for (x y) in vars collecting (cons x y))
;;; Look up a var like A a list like ((A 0) (B 1))
;;; and retrieve the (A 0). Or nil if not found.
(defun lookup-var (var bindings)
(find var bindings :key #'first))
;;; The homework
(defun subst-vars (tree bindings)
(cond
;; if the tree is a cons cell, then substitute in the
;; car, substitute in the cdr, and combine the results by consing
;; a new cons! Easy!
((consp tree) (cons (subst-vars (car tree) bindings)
(subst-vars (cdr tree) bindings)))
;; Otherwise the tree must be an atom. See if the atom is
;; a var that we can substitute. If not, return the atom.
(t (let ((binding (lookup-var tree bindings)))
(if binding
(second binding) ;; got a binding entry; return its value!
tree))))) ;; no deal, just return the original
Typed this right in the stackoverflow window and it ran with no edits. :)
This is quite inefficient though. Suppose that the variables do not occur in the tree at all. It makes a wasteful copy of the tree instead of just returning the tree. So that you do some work on this yourself, can you figure out a way to optimize it so that it avoids calling the cons function unnecessarily? Hint: check if the recursive calls to subst-vars just return the same object.

Resources