In Python, I can do something like this:
t = (1, 2)
a, b = t
...and a will be 1 and b will be 2. Suppose I have a list '(1 2) in Scheme. Is there any way to do something similar with let? If it makes a difference, I'm using Racket.
In racket you can use match,
(define t (list 1 2))
(match [(list a b) (+ a b)])
and related things like match-define:
(match-define (list a b) (list 1 2))
and match-let
(match-let ([(list a b) t]) (+ a b))
That works for lists, vectors, structs, etc etc. For multiple values, you'd use define-values:
(define (t) (values 1 2))
(define-values (a b) (t))
or let-values. But note that I can't define t as a "tuple" since multiple values are not first class values in (most) scheme implementations.
A bare-bones idiom is to use apply with lambda where you'd use let, like:
(define t '(1 2))
(apply (lambda (a b)
;; code that would go inside let
)
t)
The advantage is that it works on any implementation. Of course this can only be used on simple cases, but sometimes that's all you need.
The general term for what you're looking for (at least in Lisp-world) is destructuring and a macro that implements it is known as destructuring-bind. In Common Lisp, it works like this:
(destructuring-bind (a b c) '(1 2 3)
(list a b c)) ;; (1 2 3)
it also works for multiple "levels" of nesting:
(destructuring-bind (a (b c) d) '(1 (2 3) 4)
(list a b c d)) ;; (1 2 3 4)
It looks like there's a nice implementation of destructuring-bind as a scheme macro.
I think this is what you are looking for:
http://www.phyast.pitt.edu/~micheles/scheme/scheme16.html
Look at let-values or let+.
This works in Racket if you don't want to bring in the match dependency:
From a list:
(let-values ([(a b c) (apply values '(1 2 3))])
(+ a b c))
Or directly from a values expression:
(let-values ([(a b c) (values 1 2 3)])
(+ a b c))
Here is a simple destructuring-bind macro for schemes with case-lambda (such as Racket or Chez Scheme):
(define-syntax bind
(syntax-rules ()
((_ arg pat def body)
(apply
(case-lambda
[pat body]
[x def] )
arg ))))
Here is the example that motivated me to write this macro. Putting the default before the body makes for readable code:
(define (permutations l)
;
(define (psub j k y)
;
(define (join a b)
(bind a (ah . at) b
(join at (cons ah b)) ))
;
(define (prec a b z)
(bind b (bh . bt) z
(prec (cons bh a) bt
(psub (cons bh j) (join a bt) z) )))
;
(if (null? k)
(cons (reverse j) y)
(prec (list) k y) ))
;
(psub (list) (reverse l) (list)) )
Here are benchmarks for computing permutations of length 9, on various schemes:
0m0.211s Chez Scheme
0m0.273s Bigloo
0m0.403s Chicken
0m0.598s Racket
The translation to GHC Haskell is 5x faster than Chez Scheme. Guile is much slower than any of these schemes.
Aside from the ease of leveraging the existing case-lambda code, I like how this macro accepts exactly the same syntax as function definition argument lists. I love the simplicity of scheme. I'm old enough to remember programming Fortran on punched cards, where the allowed syntax varied wildly with context. Scheme is supposed to be better than that. The impulse is overwhelming to guild the lily on macros like this. If you can't justify changing the syntax for function definitions too, then don't change that syntax here either. Having an orthogonal grammar is important.
Related
I am still in the process of understanding macros and though I think I understand the basics of "backquote" "unquote" and "unquote splicing", I had thought they were only used/useful in macros.
however I came across this Common Lisp code from Rosetta code (the calender task),
(defun month-strings (year month)
"Collect all of the strings that make up a calendar for a given
MONTH and YEAR."
`(,(date-calc:center (month-to-word month) (length *day-row*))
,*day-row*
;; We can assume that a month calendar will always fit into a 7 by 6 block
;; of values. This makes it easy to format the resulting strings.
,# (let ((days (make-array (* 7 6) :initial-element nil)))
(loop :for i :from (date-calc:day-of-week year month 1)
:for day :from 1 :to (date-calc:days-in-month year month)
:do (setf (aref days i) day))
(loop :for i :from 0 :to 5
:collect
(format nil "~{~:[ ~;~2,d~]~^ ~}"
(loop :for day :across (subseq days (* i 7) (+ 7 (* i 7)))
:append (if day (list day day) (list day))))))))
here back-quote, unquote, and unquote splicing are used in a normal function, and it works to create a list of strings.
and while I do not use Scheme, the Racket solution had something similar,
(define days
(let ([? (if (= mn 12) (λ(x y) y) (λ(x y) x))])
(round (/ (- (find-seconds 0 0 12 1 (? (+ 1 mn) 1) (? yr (+ 1 yr))) s)
60 60 24))))
(list* (~a mname #:width 20 #:align 'center) "Su Mo Tu We Th Fr Sa"
(map string-join
(nsplit 7 `(,#(make-list pfx " ")
,#(for/list ([d days])
(~a (+ d 1) #:width 2 #:align 'right))
,#(make-list (- 42 pfx days) " ")))))))
which I did not test.
my questions are,
Why would this be necessary in a function, what is the use case?
and how is it different from a macro ?
quasiquote, unquote and unquote-splicing are just syntax sugar for a combination of quoted datum, list, and cons. Imagine this:
`(,a b c) ; == (cons a '(b c))
`(a b ,c) ; == (list 'a 'b c)
`(a b ,#c d) ; == (cons 'a (cons 'b (append c '(d))))
These are small trivial examples, so you can imagine the right hand side might become crazy complex, but it is nice to know that the quasiquote magic makes new cons when needed and keep literals as is in the tails. Thus using nconc of quasiquoted expression would not work in the first case, but in the second and third because the last cons is needed to be fresh in those cases.
If you have a function that creates a list structure, quasiquote will make the code more clear and consice since the form will look more like the result. It is no different than a macro since both create list structure. A macro differs in what happens with the result. In a function the value is returned and in a macro code gets replaced.
You can check what happens after using the macro with macroexpand:
(macroexpand '`(,a ,b ,#c))
; ==> (cons a (cons b c))
; ==> t
Backquote
See the CLHS on Backquote.
The example
The example is similar to this code:
CL-USER 14 > (let ((a 1)
(b 2)
(c '(3 4 5)))
`(,a ; a gets evaluated and put in
,b ; b gets evaluated and put in
,#c)) ; c gets evaluated and spliced in
(1 2 3 4 5)
The effect of above code is similar to using the function list*.
CL-USER 15 > (let ((a 1)
(b 2)
(c '(3 4 5)))
(list* a b c))
(1 2 3 4 5)
Which version you use is mostly a matter of taste.
list* creates a list of the first values and puts them in front of the last value, which usefully should be a list.
List creation
There are many ways and styles to create a list. The two here:
use nested functions like cons, list, list*, append, ... This is especially useful when there are many elements to be computed.
use templates of lists with the backquote operator and ,, ,#, ,. for evaluating. This is especially useful when there are nested lists with fixed objects and a few objects to compute.
Thus the backquoted way is useful when you think of list templates to fill out. Whenever you want to create (nested) lists, which are based on templates with a lost of constant structure (meaning objects and nesting), then this is a way to do it. This is not limited to macros - it is a general mechanism to build lists.
You can also think of templates being an inversion:
functions evaluate by default and constant elements need to be quoted
backquote templates don't evaluate by default and variable elements need to be unquoted.
Warning
Backquoted expressions themselves don't need to be pure lists. The internal representation of backquoted expressions is undefined and implementations actually differ.
Vectors, too
Note that this works for vectors, too:
CL-USER 20 > (let ((a 1)
(b 2)
(c '(3 4 5)))
`#(,a
,b
,#c))
#(1 2 3 4 5)
Quasi-Quote (QQ) is a list constructor in Scheme.
It’s more flexible than quote ('), list or cons because it allows for mixing symbols with expression evaluations.
The QQ has two helper mechanisms:
unquote - denoted (,)
unquote-splicing - denoted (,#)
When QQ is used, a quote context is initiated. Unquote allows us to momentarily escape the quote context and evaluate the expression right after the unquote. Unquote-splicing both escapes an entire list from the quote context as well as “unwraps” the list.
Consider:
(define b 5)
(define s (list 1 2))
Note the differences in the values of the following expressions: Quote, Quasi-Quote.
Input:
'(a b c)
`(a b c)
Output
> (a b c)
> (a b c)
Input
'(a ,b c)
`(a ,b c)
Output
> (a ,b c)
> (a 5 c)
Input
'(a ,s c)
`(a ,s c)
Output
> (a ,s c)
> (a (1 2) c)
Input
'(a ,#s c)
`(a ,#s c)
Output
> (a ,#s c)
> (a 1 2 c)
Source: Compilation course I took , The Common Lisp Cookbook - Macros and Backquote
I am attempting to write a program that checks whether or not a list of lists has a certain property (unimportant to the question). Along the way I found it necessary to produce the list of "non-diagonal pairs" of a single given list, so I wrote a macro that takes a list and defines both the list of pairs (a list-version of the Cartesian product of sets) and what I'll call the "diagonal" of that list (pairs of the form '(x x)). The code I've written to accomplish this is below:
;;;These first two definitions are 'extended' car and cdr
;;;I only did this because the (prod a b) code below threw errors otherwise
(define (xcar a) (cond ((null? a) '()) ((car a))))
(define (xcdr a) (cond ((null? a) '()) ((cdr a))))
;;;This defines a pre-product, i.e. all pairs with the first element of the first list
(define (pre-prod a b)
(cond ((or (null? a) (null? b)) '())
((append (list (list (xcar a) (xcar b))) (pre-prod a (xcdr b))))))
;;;This defines the full product of the list
(define (prod a b)
(cond ((null? a) '())
((append (pre-prod a b) (prod (xcdr a) b)))))
;;;This defines the diagonal of the list
(define (diagonal a)
(cond ((null? a) '())
((append
(list (list (car a) (car a)))
(diagonal (cdr a))))))
Great, that code all seems to work just like I want it to. I next needed to take a list-version of the set-minus. I found the following code to do exactly this in an answer here:
;;;Returns #t if x is an element of lst and #f otherwise
(define (element? x lst)
(cond ((null? lst) #f)
((eq? x (car lst)) #t)
(#t (element? x (cdr lst)))))
;;;Takes list a and removes all elements of list b from it
(define (list-minus a b)
(cond ((null? a) '())
((element? (car a) b)
(list-minus (cdr a) b))
(#t (cons (car a) (list-minus (cdr a) b)))))
Cool, that seems to work just fine for what it needs to do. Now all I have to do is get DrRacket to return the list of proper pairs (removing the diagonal). I figure that the following code ought to do it:
(define (proper-pairs a) (list-minus (prod a a) (diagonal a)))
Now I test this new function on something easy, where it should return '():
> (proper-pairs '(1))
=> '((1 1))
WHAT? I've tried a lot of examples, reworked the code several times, tried it on various lists of lists. I always come up with the following problem: list-minus will not remove a list from a list of lists.
Question 1: Why does list-minus exhibit this anomalous behavior on lists of lists while working exactly as expected on things like the following example:
> (list-minus '(1 2 3 4 5) '(x 2 4 m))
=> '(1 3 5)
Question 2: How do I repair the list-minus code, or is it necessary to start from scratch?
Question 3: In the very first lines of code above I had to "extend" the car and cdr to ensure that the prod function would not throw an error. Is what I did a standard trick? I'm not sure I understand why it makes a difference (I just tried it in because I had a hunch it might work).
Disclaimer: I am not a programmer. I'm trying to learn functional programming as a means of testing various (mathematical) conjectures and compiling some examples. I have absolutely no experience writing code other than some very silly little bits that I've done in DrRacket and on an old TI-83 calculator. This being said, it will probably be necessary to "dumb-down" your answers for me.
Sorry for the long-windedness, and thank you for your time!
The problem is due to the fact that equality in Racket, like in other languages, is represented with different operators, that must be chosen according to:
the type of data that must be compared,
the semantics of the comparison.
The general hint is that you should use the operator which is logically more simple for the task and that can be used for a certain comparison.
For instance, you should use = to compare numbers; eq? to compare objects for identity i.e. two values are equal if the are the same object in memory; eqv? if you want to check that two values are the same object in memory or are equal numbers or equal characters; equal? if you want to check if two values are eqv? or if they are equal strings, or if they, being structured data like lists, are structurally equivalent (see the manual), i.e. recursively equivalent.
For instance:
(equal? '(a (b)) '(a (b))) ; => true, two different objects with the same structure
(eqv? '(a (b)) '(a (b))) ; => false, two different objects
(eq? '(a (b)) '(a (b))) ; => false, as for eqv?
(let ((x '(a (b))))
(eq? x x)) ; true, they are the same object
So I'm currently stuck on a "simple?" function in Racket. It's using the Intermediate Student with lambda language.
Some restrictions on this are that NO recursion is allowed, neither are local functions. It's plain and simple abstract list functions.
What this function is supposed to do is to take in a list of numbers, and output a list of pairs in which each pair has the first element as the number with the second element being the number it has occurred in the list.
Examples:
(1 1 2 3) => ((1 2) (2 1) (3 1))
(2 3 4 3) => ((2 1) (3 2) (4 1))
I have a function that produces the number of occurrences by inputting a list of numbers and a number which is:
(define (occurrences lon n)
(length (filter (lambda (x) (= x n)) lon)))
My approach, which was clearly wrong was:
(define (num-pairs-occurrences lon)
(list (lambda (x) (map (occurrences lon x) (remove x lon)) x))
I thought the above would work, but apparently my lambda isn't placed properly. Any ideas?
It's a bit trickier than you imagine. As you've probably noticed, we must remove duplicate elements in the output list. For this, is better that we define a remove-duplicates helper function (also using abstract list functions) - in fact, this is so common that is a built-in function in Racket, but not available in your current language settings:
(define (remove-duplicates lst)
(foldr (lambda (e acc)
(if (member e acc)
acc
(cons e acc)))
'()
lst))
Now it's easy to compose the solution using abstract list functions:
(define (num-pairs-occurrences lon)
(map (lambda (e) (list e (occurrences lon e)))
(remove-duplicates lon)))
The above might return and output list in a different order, but that's all right. And before you ask: yes, we do need that helper function. Please don't ask for a solution without it...
An easy, self-contained solution would be:
(define (num-pairs-occurences lst)
(foldl (lambda (e r)
(if (or (null? r) (not (= (caar r) e)))
(cons (list e 1) r)
(cons (list e (add1 (cadar r))) (cdr r))))
null
(sort lst >)))
Basically, you sort the list first, and then you fold over it. If the element (e) you get is the same as the first element of the result list (r), you increment the count, otherwise you add a new sublist to r.
If you sort by > (descending), you can actually use foldl which is more memory-efficient. If you sort by < (ascending), you need to use foldr which is less efficient.
I like creating functions which take an unlimited number of arguments, and being able to deal with them as a list. It's been useful to me when creating binary trees & I'm using it for a variation on the nearest-neighbor algorithm right now. My method, however, is really horrible: since I can't think of a way to iterate over an improper list (which may well be improper & degenerate), I tried using various list functions to force the improper list into list form.
This is my best attempt in a simple function to determine difference between map-nodes (works, just not sure why it works):
(define distance-between
(lambda xs
(let ([input-list (list* xs null)])
(letrec
([f (lambda (xs acc)
(if (null? (cdr xs))
acc
(f (cdr xs)
(+ (abs (- (map-node-x (car xs))
(map-node-x (cadr xs))))
(abs (- (map-node-y (car xs))
(map-node-y (cadr xs))))
acc))))])
(f (car input-list) 0)))))
As you can see, it's an ugly solution and involves some of what seems like magic to me - why is the improper list coerced into list form when I include it in a list*? (note: this sentence is misleading, this does not occur).
I'd rather have a pretty solution and no magic. Can anyone help?
For example a typical input would be:
(distance-between (map-node 1 2) (map-node 2 3) (map-node 3 4))
with the expected result:
4
(a distance of 2 between map-node (a) and m-n (b), plus a distance of 2 between map-node (b) and map-node (c)).
Alternatively one might simply input:
(distance-between (map-node 1 2) (map-node 2 2))
and get an answer of:
1
If I attempted this on the raw input, without my (let ([input-list...])...) statement, it would cause an error as (? not actually sure why given response to this question).
The function works as expected.
There's nothing improper about the list received as a variadic argument list (meaning: variable number of arguments). For example:
(define test-list
(lambda xs
(length xs))) ; xs is a normal list, use it like any other list
(test-list 1 2 3 4)
=> 4
In the above example, the xs parameter is a normal, plain, vanilla list, there's nothing improper about it. You can iterate over it as you would over any other list. There's no need to car it, it's already a list! Also, notice that the same function can be written like this:
(define (test-list . xs)
(length xs)) ; xs is a normal list, use it like any other list
Just for reference: an improper list is one that does not end with the null list. For example: '(1 2 3 . 4). Again, that's not how a variadic argument list looks.
I also don't understand how your variadic argument list could be improper.
But to answer your original question (how to iterate over a possibly improper list, somewhat more elegantly), here is one way using match:
#lang racket
(define (properly-sum-improper-list xs)
(let loop ([acc 0]
[xs xs])
(match xs
[(list) acc]
[(cons x more) (loop (+ acc x) more)]
[x (+ acc x)]))) ;last item of improper list
(require rackunit)
(check-equal? (properly-sum-improper-list '(1 2 3 4)) 10)
(check-equal? (properly-sum-improper-list '(1 2 3 . 4)) 10)
However needing to do this, at all, is probably an indication you want to fix or change something else.
Your list is not improper. When your argument is not a pair, like (lambda xs body ...) or (define (fun . xs) body ...) all your arguments gets slurped into a list. Eg.. (fun 1 2 3) would make xs '(1 2 3). Doing (list* '(1 2 3) '()) makes '((1 2 3) which you undo right away by calling your loop with car which makes it '(1 2 3) again.
Other than that your procedure works as intended. You might clean up your procedure a little, but since there is no list comprehensions that glides over a list folding over the two next elements it won't become much smaller. Below is basically the same code, but abstracting out the procedure that does the work (which if existed a foldl-pair you could have used) and with a named let as a iterator loop (which is syntactic sugar for a letrec+call).
(define (distance-between e1 . lst)
(define (add-diff-acc e1 e2 acc)
(+ (abs (- (map-node-x e1) (map-node-x e2)))
(abs (- (map-node-y e1) (map-node-y e2)))
acc))
(let iterate ((e1 e1) (lst lst) (acc 0))
(if (pair? lst)
(let ((e2 (car lst)))
(iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
acc)))
EDIT: About syntax sugar, named let and letrec.
(let ((x 10) (y 19))
body)
is syntactic sugar for a anonymous procedure call
((lambda (x y)
body)
10 19)
A named let is just giving that procedure a name, though as if by letrec, making a recursive binding. you call it with the name you give and the arguments will be what you supply instead of the initial value in the let. I'm used to them and prefer them today. It might take some time to get used to though.
Most of the code we write is syntactic sugar for some lower level stuff. The macros are nested so that your letrec form could get reduced down lambdas eventually. The whole procedure without syntactic sugar would look like this:
(define distance-between
(lambda (e1 . lst)
((lambda (add-diff-acc)
((lambda (iterate e1 lst acc) ; emulate Y to substitute `letrec`
(iterate iterate e1 lst acc))
(lambda (iterate e1 lst acc)
(if (pair? lst)
((lambda (e2)
(iterate iterate e2 (cdr lst) (add-diff-acc e1 e2 acc)))
(car lst))
acc))
e1 lst 0))
(lambda (e1 e2 acc)
(+ (abs (- (map-node-x e1) (map-node-x e2)))
(abs (- (map-node-y e1) (map-node-y e2)))
acc)))))
I am learning how to use higher-order functions in scheme. I get the idea of using higher-order functions, however I am having trouble using them. For this learning exercise, I would prefer to only use some combination of filter, fold, and/or map.
For example, I want to construct the set difference between two lists call them A and B. I am defining set difference as x such that x is an element of A but x is not an element of B. I only want to use the functions map, filter and fold. For example:
Let A = (1 8 6 2)
Let B = (5 7 9 1 6)
The set difference of A and B would be (8 2)
The idea is to construct a new list by iterating over the elements of A and seeing if an element of A equals an element of B, if so don't add a to the new list; otherwise add a to the new list.
My algorithm idea goes something like this:
Let neq be "not equal to"
For each a in A and b in B evaluate the expression: (neq? a b)
For a = 1 we have:
(and (neq? 1 5) (neq? 1 7) (neq? 1 9) (neq? 1 1) (neq ? 1 6))
If this expression is true then a goes in the new list; otherwise don't add a to the new list. In our example (neq? 1 1) evaluates to false and so we do not add 1 to the new list.
Pretty much my entire procedure relies on 1, and this is where I have a trouble.
How do I do step 1?
I see that in step 1 I need some combination of the map and fold functions, but how do I get the and a neq b distributed?
EDIT This is the closest sample I have:
(fold-right (trace-lambda buggy (a b c) (and (neq? a b))) #t A B)
|(buggy 3 5 #t)
|#t
|(buggy 2 4 #t)
|#t
|(buggy 1 1 #t)
|#f
#f
The above shows a trace of my anonymous function attempting to perform the (and (neq? a b)) chain. However, it only performs this on elements in A and B at the same position/index.
All help is greatly appreciated!
A simplified version of member is easy to implement using fold, of course:
(define (member x lst)
(fold (lambda (e r)
(or r (equal? e x)))
#f lst))
Now, with that, the rest is trivial:
(define (difference a b)
(filter (lambda (x)
(not (member x b)))
a))
If you want to amalgamate all that into one function (using your neq?), you can do:
(define (difference a b)
(filter (lambda (x)
(fold (lambda (e r)
(and r (neq? e x)))
#t b))
a))
In Haskell, fold is capable of short-circuiting evaluation because of lazy evaluation.
But in Scheme it is impossible. That's why in Racket e.g., there's a special function supplied for that, ormap, which is capable of short-circuiting evaluation. IOW it is a special kind of fold which must be defined explicitly and separately in Scheme, because Scheme is not lazy. So according to your conditions I contend it is OK to use it as a special kind of fold.
Using it, we get
(define (diff xs ys)
(filter
(lambda (y)
(not (ormap (lambda (x) (equal? x y)) ; Racket's "ormap"
xs)))
ys))
If your elements can be ordered, it is better to maintain the sets as ordered (ascending) lists; then diff can be implemented more efficiently, comparing head elements from both lists and advancing accordingly, working in linear time.
Using Racket:
(define A '(1 8 6 2))
(define B '(5 7 9 1 6))
(filter-not (lambda (x) (member x B)) A)
==> '(8 2)
Of course, it is possible in Scheme to implement member on top of fold that short-circuits on the first match:
(define (member x lst)
(call-with-current-continuation
(lambda (return)
(fold (lambda (e r)
(if (equal? e x)
(return #t)
r))
#f lst))))