About unpack in fennel-lang - group-by

Recently, I used fennel to write neovim config, and I couldn’t understand the usage of unpack when referring to someone’s project.
(fn group-by [n seq ?from]
(fn f [seq i]
(let [i (+ i n)
j (+ i n -1)]
(when (< i (length seq))
(values i (unpack seq i j)))))
(let [start-idx (if (nil? ?from) 1 ?from)]
(values f seq (- start-idx n))))
I read the fennel referenece, not found this usage of unpack.

unpack seems to be a way to take a table of values and unpack them as individual values inside an expression:
(let [(x y z) (unpack [10 9 8])]
(+ x y z)) ; => 27
Here above, unpack works on a list of three elements (a single value) and returns 3 values (10, 9 and 8), which are bound to x y and z respectively thanks to the let binding.
Usually, you can call values as follows to return multiple values:
(values 1 2 3)
But in your case, (values i (unpack ...)) is a form that returns multiple values where the amount of values to return is not know in avance and depends on the size of the list/table being given to unpack during execution.

Related

Nested lists in Lisp comparison

I have a function that can produce a list of n-element sublists from a list of elements but I am stuck in filtering out elements that are just permutations of each other. For example, f(A,B) -> ((A, B) (B,A)) is what I get but I just want ((A,B)) since (B,A) is a permutation. Is there a lisp function for this? I don't need the whole answer but a clue would be appreciated, note that A,B need not be atoms but can be string literals and even lists themselves.
I am doing this
(let (newlist '())
(loop :for x in l1 :do
(loop :for y in l2 :do
(push (list x y) newlist)))
... and I have another function that filters out these duplicates but it is clunky and probs won't scale for large inputs.
One interesting function is the (destructive) pushnew which pushes an element to a list only if it is not already existent in the set (list).
(defun pair-comb (l1 l2 &key (test #'eql) (key #'identity))
(let ((result '()))
(loop for x in l1 do
(loop for y in l2 do
(pushnew (list x y) result :test test :key key))
finally (return result))))
When we make the comparison between the elements in a way that it is order-agnostic, we would have the perfect function for us to collect different lists while ruling out the permutations of any of the already collected lists.
This can be done by #'sort-ing each list and compare by #'equalp or whatever equality function.
(pair-comb '(1 2 3) '(1 2 3 4 5) :test #'equalp :key (lambda (x) (sort x #'<)))
;;=> ((3 5) (3 4) (3 3) (2 5) (2 4) (2 3) (2 2) (1 5) (1 4) (1 3) (1 2) (1 1))
;; well, actually in this case #'eql would do it.
;; when using non-numeric elements, the `#'<` in sort has to be changed!

Unused Lexical Variable

Just started learning lisp. I have no idea why I am getting these errors or even what they mean. I am simply trying to code an approximation of pi using the Gregory-Leibniz series, here is the code.
(defun gl (n)
(defparameter x 0) ;init variable to hold our runnning sum
(loop for y from 0 to n ;number of iterations, starting from 0 to desired n
(if (= y 0) ;if n is 0 then we just want 4
(defparameter w 4))
(if (> y 0) ;else, 4*(-1^y)/((2 * y)+1)
(defparameter w (* 4 (/ (exp -1 y) (+ (* 2 y) 1)))))
(+ x w)) ;add to our running sum
(write x)) ;once loop is over, print x.
I have tried using setq, defvar, let etc. instead of defparameter but I still get "Undeclared free variable X".
I also get the error "Unused lexical variable N" even though I am using it for my loop, which is weird also.
How can I fix this and why is it happening? Thanks!
Here is the code after Emacs auto-indented it:
(defun gl (n)
(defparameter x 0)
(loop for y from 0 to n
(if (= y 0)
(defparameter w 4))
(if (> y 0)
(defparameter w (* 4 (/ (exp -1 y) (+ (* 2 y) 1)))))
(+ x w))
(write x))
Compiling the following code with SBCL gives one error and two warnings.
One warning says that x is undefined.
You should not call defparameter from inside your function, since defvar and defparameter are used to declare dynamic variables and to set their value in the global scope. Prefer to have let bindings, or, since you already are using a loop, a with clause. When you want to modify a binding, use setf.
The errors comes from the macroexpansion of LOOP, which is malformed. For SBCL, that means that the code is treated as dead-code for the rest of the function compilation; that explains why n appears not to be used, which is what the second warning is about.
There are various fixes remaining to be done:
Use function EXPT, not EXP.
Calling (+ x w) only computes a value but does not modify x, the result is useless.
Prefer using if as expression, like a ternary operator in other languages, in your case the code can be simplified
Adding one can be done with function 1+ (that's the name of the function, not a special syntax for adding constants)
The write operation is rarely needed, especially if you are computing a mathematical formula; just return the value, and the REPL will print it automatically.
Small corrections that make your code works:
(defun gl (n)
(let ((x 0))
(loop
for y from 0 to n
for w = (if (= y 0)
4
(* 4 (/ (expt -1 y) (+ (* 2 y) 1))))
do (setf x (+ x w)))
(write x)))
I would personally get rid of x and w, and use a SUM loop clause.
(defun gl (n)
(loop
for y from 0 to n
sum (if (zerop y)
4
(* 4 (/ (expt -1 y)
(1+ (* 2 y)))))))

Can anyone help me with a recursive function in racket?

I am writing a recursive function. But the question requires you not to use the exponential function. Can anyone show me how to get larger powers by multiplying smaller powers by a?
Input a=2 n=4. Then get[2, 4, 8, 16]
Input a=3 n=4. Then get[3 9 27 81].
I was trying to multiply a by a each time, so when I input 2 and 4. I get [2 4 16 256]. So what should I do?
Here is what I have written:
(define (input a n)
(if (= n 0)
'()
(append (cdr (list [* a a] a))
(let ((a (* a a)))
(input a (- n 1))))))
You are approaching the problem wrong, you really need two recursive functions (one to build the list and one to build each element). I am assuming you are allowed to use local, but if you aren't you could move that into a helper function.
(define (build-sqr-list a n)
(local [(define (sqr-recurse a n)
(if (= n 0)
1
(* a (sqr-recurse a (sub1 n)))))]
(if (= n 0)
'()
(cons (sqr-recurse a n) (build-sqr-list a (sub1 n))))))

Common Lisp - Gentle introduction to symbolic computation: Excercise 4.4

I am learning Common Lisp using clisp and have entered following code:
(defun ordered (x y)
(if (< x y)
(list x y)
(list y x)))
(setq l (ordered 28 49))
(print l)
(setq l (ordered 49 28))
(print l)
Expected these answers:
(28 49)
(49 28)
Got these answers:
(28 49)
(28 49)
In the solutions of this book I have found the same function definition.
What could be wrong?
Your code
(defun
defines a function,
ordered
named "ordered",
(x y)
that expects two arguments which will be known as "x" and "y" in its body, whereupon on receiving the arguments (i.e. having been called with two values, e.g. (ordered 49 28))
(if (< x y)
it will compare them, and in case the first was smaller than the second, it will produce
(list x y)
the same two values repackaged in a list (i.e. '(49 28)); or otherwise, if the first value was not smaller than the second,
(list y x)))
it will produce the list containing the second value first, and then the first argument value (i.e. '(28 49)).
So, which was the case here, of comparing the 49 and 28?
Reading this code generally, we can say that if it receives the smaller number as its first argument, it will produce the smaller number first and the bigger number second, in the result list;
and in case it receives the smaller number as its second argument, it will produce the smaller number first and the bigger number second, in the result list.
Reading this back, we can see that this description can be simplified further into one simple statement: it will always produce ______ number first, and ______ second, in the resulting list.
Another way to attack this, is to write down the function created by that definition,
( lambda (x y) (if (< x y) (list x y) (list y x) ) )
Then follow its application symbolically:
( ( lambda (x y) (if (< x y) (list x y) (list y x) ) )
49
28 )
==
(let ( (x 49)
(y 28)
)
(if (< x y) (list x y) (list y x) ) )
==
(let ( (x 49)
(y 28)
)
(if (< 49 28) (list x y) (list y x) ) )
==
(let ( (x 49)
(y 28)
)
(if FALSE (list x y) (list y x) ) )
==
(let ( (x 49)
(y 28)
)
(list y x) )
==
(let ( (x 49)
(y 28)
)
(list 28 49) )
==
(list 28 49)

Scheme - how to find index of character while going through string

Having a problem with a function I'm writing in Scheme. The method takes a word represented as list of symbols as input, and for each character, does a hashing equation and returns a value. The final value is the sum of the hash value for each character in the set.
Imagine a string as an array of characters, 'w', where w[i] is the index of each character in the array.
The equation is the sum of --> 7^i * ctv(w[i]) for each character in the word.
For each letter where ctv (“character-to-value”) maps ‘a’ to 1, ‘b’ to 2, ... and ‘z’ to 26.
For example, key(“d a y”)
= (7^0 * ctv (’d’)) + (7^1 ctv(‘a’)) + (7^2 ctv(‘y’)) = 1236
SO, my actual question about this is how I find the index, the i in w[i] for each character in the word.
Here is my first thought, using (length w) as the index but I know this is incorrect.
(define keys
(lambda(w)
(if(null? w)
0
(+ (* (ctv(car w)) (expt 7 (length w))) (keys (cdr w)))))
)
My next thought was maybe it a lambda for size, like this.
Note - I know it would need to be changed to (size-1).
(define keys
(lambda(size)
(lambda(w)
(if(null? w)
0
(+ (* (ctv(car w)) (expt 7 (size w))) (keys (cdr w)))))
)
But even then, the size would still the be opposite end of the index, for example with 'day', size-1 for 'd' would be 2, and size-1 for 'y' would be 0.
Anyway, if anyone has any idea what I'm talking about and has a possible solution or advice, please reply!!
The trick here is to pass along the index as a parameter, and increment it at the same time that you traverse the list. Also, it's easier if we transform the input string into a list of chars, For example:
(define (key word)
(let loop ((chars (string->list word)) ; list of chars
(idx 0) ; current index
(acc 0)) ; accumulated result
(if (null? chars) ; if the list is empty
acc ; return the accumulator
(loop (cdr chars) ; otherwise go to the next char
(add1 idx) ; advance the index
(+ acc (* (expt 7 idx) (ctv (car chars)))))))) ; compute result
Assuming that the ctv procedure is correctly implemented, it should work as expected:
(key "day")
=> 1236
Since this question is also tagged Racket, you might appreciate an elegant, Racket-only solution using for/sum and in-indexed:
(define (key word)
(for/sum (((c i) (in-indexed word)))
(* (expt 7 i) (cvt c))))
Testing:
> (key "day")
1236