Append list from assoc to another list in Scheme - scheme

I'm a bit confused on how to append a list that I've gotten from the assoc procedure into another list, here is what I have:
(define new-list (list 'test))
(define source-a (list '(a foo) '(b bar) '(c hello)))
(append new-list (assoc 'a source-a))
(display new-list)
The output is just (test) and I'm not sure why it's not (test a foo). Is it possible to append like this?

That's because append is not a mutating function. It returns a new list with its arguments appended together. By convention in Scheme, functions that perform mutation end with an exclamation mark, such as set!.
You can use set! to modify new-list so that it is updated, like this:
(set! new-list (append new-list (assoc 'a source-a)))
However, this is highly discouraged in Scheme. While imperative programming makes heavy use of mutation, functional programming languages (including Scheme) try to avoid mutation and side-effects, since those can make programs harder to reason about.
Ideally, you'd just declare a new binding with the new value instead of updating an existing binding. Something like this would work just fine:
(define original-list (list 'test))
(define source-a (list '(a foo) '(b bar) '(c hello)))
(define new-list (append original-list (assoc 'a source-a)))
(display new-list)

Related

Can someone explain equality to me in scheme/racket?

So I stumbled across this today and it has me puzzled.
(define (x) '(1))
(eq? (x) (x)) ;=> #t
(eq? '(1) '(1)) ;=> #f
(define (y) (list 1))
(eq? (y) (y)) ;=> #f
(eq? (list 1) (list 1)) ;=> #f
Can anyone explain what's happening here ?
When compiled this program
(define (x) '(1))
(eq? (x) (x))
(eq? '(1) '(1))
is compiled into (something like):
(define datum1 '(1))
(define datum2 '(1))
(define datum3 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum2 datum3)
Therefore (x) will always return the object stored in datum1.
The expressions (eq? '(1) '(1)) on the other hand will
find out that datum2 and datum3 does not store the same object.
Note: There is a choice for the compiler writer. Many Scheme implementation will compile the above program to:
(define datum1 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum1 datum1)
and then the result will be true in both cases.
Note: The documentation of quote doesn't explicitly state whether multiple occurrences of '(1) in a program will produce the same value or not. Therefore this behavior might change in the future. [Although I believe the current behavior is a deliberate choice]
eq? checks if the objects are the same (think "if the pointer refers to the same address in memory").
In the first case you're working with literals created at compile time. Comparing (and modifying) literals is generally undefined behaviour. Here it looks like procedure x returns the same literal every time, but in the second expression it looks like the 2 literals are not the same. As I said, undefined behaviour.
In the second case you're not working with literals but list creates a new list at execution time. So each call to y or list creates a fresh list.
uselpa's answer is correct.† I wanted to expand on what a quoted datum is, a little further, though.
As you know, all Scheme programs are internally read in as a syntax tree. In Racket, in particular, you use the read-syntax procedure to do it:
> (define stx (with-input-from-string "(foo bar)" read-syntax))
> stx
#<syntax::1 (foo bar)>
You can convert a syntax tree to a datum using syntax->datum:
> (syntax->datum stx)
'(foo bar)
quote is a special form, and what it does is return the quoted portion of the syntax tree as a datum. This is why, for many Scheme implementations, your x procedure returns the same object each time: it's returning the same portion of the syntax tree as a datum. (This is an implementation detail, and Scheme implementations are not required to have this behaviour, but it helps explain why you see what you see.)
And as uselpa's answer says, list creates a fresh list each time, if the list is non-empty. That's why the result of two separate non-empty invocations of list will always be distinct when compared with eq?.
(In Scheme, the empty list is required to be represented as a singleton object. So (eq? '() '()) is guaranteed to be true, as is (eq? (list) '()), (eq? (cdr (list 'foo)) (list)), etc.)
† I would not use the phrasing "undefined behaviour" for comparing literals because that's easily confused with the C and C++ meaning of UB, which is nasal demons, and although the result of comparing literals may not be what you expect, it would not cause your program to crash, etc. Modifying literals is nasal demons, of course.

The Little Schemer: What is a function or argument's structure?

In Chapter 3 of The Little Schemer, the answer to the question of why we don't simplify the rember function right away is "because then a function's structure does not coincide with its argument's structure." I'm having trouble understanding what a function's structure is, what an argument's structure is, and what the difference is between them.
Here's the unsimplified version:
(define rember
(lambda (a lat)
(cond
((null? lat) (quote ()))
(else (cond
(( eq? (car lat) a) (cdr lat))
(else (cons (car lat)
(rember a
( cdr lat)))))))))
And here's the simplified:
(define rember
(lambda (a lat)
(cond
((null? lat) (quote ()))
((eq? (car lat) a) (cdr lat))
(else (cons (car lat)
(rember a (cdr lat)))))))
From what I can tell, the main difference is that the function has gone from two conds asking one question each to one cond asking two questions.
The function's arguments are the atom "a" and the list "lat."
This is the first time, outside of the densely written foreword, where the book references the word "structure." In my mind, the definition of the word "structure" so far is open to interpretation.
Someone has asked this exact question here before, but I have trouble following the answer. Why does a two-cond structure coincide or not coincide with the structure of a list? A list, in my mind, doesn't have any conditions at all!
Isn't a condition equivalent to a question in Scheme? Perhaps I'm misunderstanding what a condition is, which could be a reasonable root of my frustration. Anyways, any clarification on this would be very much appreciated! Thank you!
Here for “structure of function” the author probably means that the body of the function, that is the condition:
(cond
((null? lat) ...)
(else ... (cond... (car lat) ... (cdr lat) ...)))
patterns exactly the “recursive” definition of a list, as either:
an empty list, or
a value with at least one element (the car), and a list (the cdr).
The new definition instead “folds” the two cond inside a single one, so that the “structure” of the function (the structure of the cond) does not reflect any more the “structure” of its list argument.
List is a type that could have been defined, with some pseudocode, as
(define-variant-record list
( () ) ; '() is a list
((hd . tl) ; a cons pair (with car field named `hd` and cdr `tl`)
(list tl)) ) ; is a list, if `tl` itself is a list
Then, it could be handled with a hypothetical (cf. EOPL) patern-matching construct variant-case:
(define rember
(lambda (a lat) ; an atom and a list of atoms
(variant-case (lat) ; follow the `lat` --
( () ; an empty list case, or
(quote ()))
( (hd . tl) ; a non-empty list, with car field `hd` and cdr `tl`
(cond
(( eq? hd a) tl)
(else
(cons hd
(rember a tl))))))))
which, by way of using the variant-case belonging to the data-type definition of list, naturally and visibly follows its structure (i.e. the two cases of its definition).
The first formulation (with the nested conds) just emulates the non-existent variant-case with the explicit access to the concrete data-type implementation, with the cars and the cdrs as it does.
The inner cond does not belong to this, and just deals with the specifics of rember on its own. That's why mashing the two conds into one may be seen as mixing the non-related concerns into one mish-mash (generally speaking; although here both are extremely simple and clear).

Maximum recursion error [duplicate]

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

I have got this code to remove the last element of a list. How can i change this to remove a set word regardless of its location?

#lang racket
(define (remove-last lst)
(if (null? (cdr lst))
'()
(cons (car lst) (remove-last (cdr lst)))))
(remove-last '(Help Me Please))
This then prints out:
(Help Me)
How can I change this? For example if I wanted to remove me.
Like this, for example:
(define (remove-words lst words)
(cond
((null? lst)
'())
((member (car lst) words)
(remove-words (cdr lst) words))
(else
(cons (car lst) (remove-words (cdr lst) words)))))
then
> (remove-words '(Help Me Please) '(Me Help Not))
'(Please)
You can also use the procedures for sets:
(define (remove-words lst words)
(set-subtract lst words))
Please note that you are working with symbols here, not strings.
You can also solve the problem using filter-not and member together:
(define (remove-words lst words)
(filter-not (lambda (x) (member x words) lst))
If you want to cut down on the wordiness of that anonymous function, the tools most suited to that are curry and cut (with the latter needing a (require srfi/26) to use).
Currying a function turns it into a new function that accepts one argument, then returns another function that accepts one more argument, then again, then again, and so on until it has all the arguments it needs to call the original function. A curried version of remove-words would be called as ((remove-words lst) words) instead, and you could make it from our current implementation with (curry remove-words). This requires that the arguments be supplied in left to right order, which doesn't work for member. There's another form curryr that goes right-to-left, but because member takes an optional third argument it won't work.
You could use cut (from srfi 26) then, which lets you pick which arguments of a function you want to "lock-in" and which you want the new function to accept. (cut member <> words)creates a new function (lambda (arg) (member arg words)) and (cut * <> <> 8) creates (lambda (arg1 arg2) (* arg1 arg2 8)). So with this, remove-words looks like:
(require srfi/26)
(define (remove-words lst words)
(filter-not (cut member <> words) lst))
Although going with set-subtract is still probably the best solution since you should avoid reinventing the wheel as much as possible (unless you're trying to learn more about wheels). Nonetheless, it's very useful to have a firm grip on the general functions provided by Racket that make your life easier.

"cond","and" and "or" in Scheme

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

Resources