In MIT Scheme, What is the difference between (null? lst) and (null? (cdr lst))? - mit-scheme

I am currently going through SICP and I am having a hard time understanding the difference between the two expressions below. Assume we have a list, called lst, What is the difference between:
(null? lst) and (null? (cdr lst))
I know that the first expression checks if the list is empty. But doesn't the second expression check for the same condition as well? In other words checks if the rest of the list is empty.

No, they are no the same thing, (null? lst) just checks whether lst is empty or not. Whereas(null? (cdr lst)) checks whether lst has only one element, since (cdr lst) returns lst with everything but the first element. See examples below.
> (null? '())
#t
> (null? '(1))
#f
> (null? (cdr '(1)))
#t
> (null? (cdr '(1 2)))
#f

Related

How can I return symbols based on the sum of lists?

So I am new to Scheme and have encountered a problem. What I am trying to do is the following. It's a rather simple problem nevertheless I am receiving several errors:
I try to sum up the elements of lists (which only consists of numbers). If the total amount is even, the procedure should return <'divisible_by_2>.
If the total amount is odd, it should return <'not_divisible_by_2>.
The initial sstep was to build a procedure that sums up the lists. This one works. The second step was to build an if function which takes the sum of lists and returns <'divisible_by_2> if the sum is even and <'not_divisible_by_2> if it is odd.
What I wrote so far:
(define (divisible_or_not list-sum lst)
(if (odd? list-sum lst)
(lambda (list-sum lst)
(cond
((null? lst)
0)
((pair? (car lst))
(+(list-sum (car lst)) (list-sum (cdr lst)))
(else
(+ (car lst) (list-sum (cdr lst)))
)
)
)
('divisible_by_2)
('not_divisible_by_2)
)
)
)
Version 2.0 (lst=tree; tree-count=sum-lst):
(define (divisible-or-not tree)
(define (tree-count tree)
(cond
((null? tree)
0)
((pair? (car tree))
(+(tree-count (car tree)) (tree-count (cdr tree)))
(else
(+ (car tree) (tree-count (cdr tree))))))
(if (odd? tree-count tree)
('divisible-by-2)
('not-divisible-by-2))))
Your code, properly indented, looks like so:
(define (divisible_or_not list-sum lst)
(if (odd? list-sum lst)
(lambda (list-sum lst)
(cond
((null? lst)
0)
((pair? (car lst))
(+(list-sum (car lst)) (list-sum (cdr lst)))
(else
(+ (car lst) (list-sum (cdr lst))))))
('divisible_by_2)
('not_divisible_by_2))))
The structure of your program looks like this:
(if ...
(lambda (...) ...))
In other words, if your test succeeds, you return an anonymous function, and if the test fails, you return nothing (in Scheme, the value is undefined in that case).
Inside your lambda, the code is a list of three expressions, a cond, the form ('divisible_by_2) and the form ('not_divisible_by_2).
First of all, do not use underscores for separating words in Lisp/Scheme, use dashes, like so: divisible-by-2.
Secondly, only the last expression's value is returned from the lambda, so the intermediate cond, since it has no side-effect, is basically doing work for nothing. The second form, ('divisible_by_2), looks like a function call but is going to give you an error. If you want to return a symbol, just quote it, without parentheses: 'divisible-by-2.
Since you already have an intermediate function, you can associate it to a name:
(define tree-count (sum tree)
(cond ...))
I named it tree-count because you also recurse into the car of your lists.
Once you have this function, you only need to apply it:
(if (even? (tree-count tree))
'divisible-by-2
'not-divisible-by-2)

Calculating the number of matches for every sublist separately

Here is my big list with sublists:
(define family
(list
(list 'Daddy 't-shirt 'raincoat 'sunglasses 'pants 'coat 'sneakers)
(list 'Mamma 'high-heels 'dress 'pants 'sunglasses 'scarf)
(list 'son 'pants 'sunglasses 'sneakers 't-shirt 'jacket)
(list 'daughter 'bikini 'Leggings 'sneakers 'blouse 'top)))
And i want to compare family with this simple list:
(list 'sneakers 'dress 'pants 'sunglasses 'scarf)
each matching should give 1 point and i want that the point to be calculated separately for each sublist.
Here is the code:
;checking if an element exists in a list
(define occurs?
(lambda (element lst)
(cond
[(and (null? element) (null? lst))]
[(null? lst) #f]
[(pair? lst)
(if
(occurs? element (car lst)) #t
(occurs? element (cdr lst)))]
[else (eqv? element lst)])))
;--------------------------------------
; a list of just names are created.
(define (name-list lst)
(list (map car lst)))
; Each sublist has a name (car of the sublist). The name-list turn to point-list for each sublist. All of my code except the code below is functioning as i want. The problem lies within point-list code.
(define (point lst db)
(let ((no-point (name-list db)))
(cond ((or (null? lst) (null? db)) '())
(set! (first no-point) (comp lst (rest db)))
(else (point lst (cdr db))))))
Daddy-sublist has 3 elements in common. Mamma-sublist has 4 elements in common, son-sublist 3 elements and daugther-sublist 1 element.
I want the outdata to be like this:
> (comparison (list 'sneakers 'dress 'pants 'sunglasses 'scarf) family)
'(3 4 3 1)
My code is not functioning as I want it. I get this Eror :
set!: bad syntax in: set!
Can someone guide explain me what to do?
You have bad syntax with set!:
(set! (first no-point-lst) (comparison lst (rest db)))
This is an invalid use of set!, attempting to "mutate the structure" of the list no-point-lst, changing what's actually held in its first position.
set! can't do that. It can be used to change a binding, i.e. the value of a variable: (let ((a 1)) (set! a 2)).
In Common Lisp they can write (setf (first list) newval), but not in Scheme / Racket.
If this is essential to your algorithm, you can use set-car! in R5RS Scheme, or set-mcar! in Racket. Or you could do this with vectors.
But you could also restructure your code as
(set! no-points-list
(cons
(comparison lst (rest db))
(cdr no-points-list)))

How to debug "List contains heterogenous data types" in Racket?

Here is my Racket problem:
Define a function that takes a list as an argument. It should return a boolean (i.e. #t or #f) indicating whether the list is sorted in ascending order. You may not use the built-in sorted? function. Your implementation must be recursive.
Input: A list of elements of homogenous data type, either numbers or strings.
Output: A boolean value that indicates whether the elements of the list are sorted in strictly increasing order. If the list contains heterogenous data types, then throw an error (using the error function) with the message “ERROR: List contains heterogenous data types”.
So when I type this function have to gave me this ERROR
(my-sorted? '(7 "spam" 9))
! ERROR: List contains heterogenous data types
BUT for mine its gave me this
(my-sorted? '(7 "spam" 9))
: contract violation
expected: real?
given: "spam"
argument position: 2nd
other arguments...:
Here what I have
(define (my-sorted-int? lst)
(define size (length lst))
(if (< size 2)
#t
(if (null? lst)
#t
(if (> (car lst) (car (rest lst))) <======= Gave me Error
#f
(my-sorted-int? (rest lst) )))))
(define (my-sorted-string? lst)
(define size (length lst))
(if (< size 2)
#t
(if (null? lst)
#t
(if (string>? (car lst) (car (rest lst)))
#f
(my-sorted-string? (rest lst) )))))
(define (my-sorted? lst)
(if (string? (car lst))
(my-sorted-string? lst)
(my-sorted-int? lst)))
So you know the left side is a number since it was the value you initially checked, but the right side also needs to be a number to be able to do > on it. Thus you need something like:
(if (number? (cadr lst))
(if (> (car lst) (cadr lst)) ...)
(error "ERROR: List contains heterogenous data types"))
You might want to use cond to get a flatter structure. Also you have made two identical procedures to deal with integers and strings when you could just made one and pass the things that are different to make your code more DRY:
(define (my-sorted? lst)
(define (my-helper? correct-type? greater-than?)
(let loop ((e (car lst))
(lst (cdr lst)))
(cond ((null? lst) #t)
((not (correct-type? (car lst)))
(error "ERROR: List contains heterogenous data types"))
((greater-than? e (car lst)) #f)
(else (loop (car lst) (cdr lst))))))
(cond ((null? lst) #t)
((string? (car lst)) (my-helper? string? string>?))
(else (my-helper? number? >))))

Searching lists that contain lists or conses

Lets say that we got a list like this(with much more elements but the method should be the same):
(define l '((cons 'name 'john)
(cons 'sur 'asurname)
(cons 'name 'george)
(cons 'sur 'georgesurname)))
and we can always add more elements to the existing list. Which is the most effective way lets say to write a function that takes the name of a the user and returns the surname:
something like :
(define display-surname
(lamdba (name)
(...)))
What is the general practice in such cases? Can anyone point an example/link of a how to?
It'd be a better idea to represent each record (name,surname) in a single list, and then handle your data as a list of lists of pairs:
(define lst '(((name . a) (sur . b)) ((name . c) (sur . d))))
With the above representation, finding a name (given a surname) is as simple as this (assuming that each field in the record is always found in the same position):
(define display-surname
(lambda (lst name)
(cond ((null? lst) #f)
((eq? (cdaar lst) name) (cdadar lst))
(else (display-surname (cdr lst) name)))))
You can simplify things even further (again assuming that each field in the record is always in the same position) by representing the above data as follows, with the corresponding changes in display-surname:
(define lst '((a . b) (c . d)))
(define display-surname
(lambda (lst name)
(cond ((null? lst) #f)
((eq? (caar lst) name) (cdar lst))
(else (display-surname (cdr lst) name)))))
Either way, this works:
(display-surname lst 'a)
> 'b
(display-surname lst 'x)
> #f

Scheme Function to reverse elements of list of 2-list

This is an exercise from EOPL.
Procedure (invert lst) takes lst which is a list of 2-lists and returns a list with each 2-list reversed.
(define invert
(lambda (lst)
(cond((null? lst )
'())
((= 2 (rtn-len (car lst)))
( cons(swap-elem (car lst))
(invert (cdr lst))))
("List is not a 2-List"))))
;; Auxiliry Procedure swap-elements of 2 element list
(define swap-elem
(lambda (lst)
(cons (car (cdr lst))
(car lst))))
;; returns lengh of the list by calling
(define rtn-len
(lambda (lst)
(calc-len lst 0)))
;; calculate length of the list
(define calc-len
(lambda (lst n)
(if (null? lst)
n
(calc-len (cdr lst) (+ n 1)))))
This seems to work however looks very verbose. Can this be shortened or written in more elegant way ?
How I can halt the processing in any of the individual element is not a 2-list?
At the moment execution proceed to next member and replacing current member with "List is not a 2-List" if current member is not a 2-list.
The EOPL language provides the eopl:error procedure to exit early with an error message. It is introduced on page 15 of the book (3rd ed.).
The EOPL language does also include the map procedure from standard Scheme. Though it may not be used in the book, you can still use it to get a much shorter solution than one with explicit recursion. Also you can use Scheme's standard length procedure.
#lang eopl
(define invert
(lambda (lst)
(map swap-elem lst)))
;; Auxiliary Procedure swap-elements of 2 element list
(define swap-elem
(lambda (lst)
(if (= 2 (length lst))
(list (cadr lst)
(car lst))
(eopl:error 'swap-elem
"List ~s is not a 2-List~%" lst))))
So it seems that your version of invert actually returns a list of different topology. If you execute (invert ...) on '((1 2) (3 4)), you'll get back '((2 . 1) (4 . 3)), which is a list of conses, not of lists.
I wrote a version of invert that maintains list topology, but it is not tail-recursive so it will end up maintaining a call stack while it's recursing.
(define (invert lst)
(if (null? lst)
lst
(cons (list (cadar lst) (caar lst))
(invert (cdr lst)))))
If you want a version that mimics your invert behavior, replace list with cons in second to last line.
If you want it to exit early on failure, try call/cc.
(call-with-current-continuation
(lambda (exit)
(for-each (lambda (x)
(if (negative? x)
(exit x)))
'(54 0 37 -3 245 19))
#t))
===> -3
(Taken from http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_idx_566)
What call-with-current-continuation (or call/cc, for short) does is pass the point where the function was called in into the function, which provides a way to have something analogous to a return statement in C. It can also do much more, as you can store continuations, or pass more than one into a function, with a different one being called for success and for failure.
Reverse list containing any number or order of sub-lists inside.
(define (reverse! lst)
(if (null? lst) lst
(if (list? (car lst))
(append (reverse! (cdr lst)) (cons (reverse! (car lst)) '()))
(append (reverse! (cdr lst)) (list (car lst))))))