contract violation in my implementation of "map" - scheme

I'm beginning in Scheme (actually, Racket with DrRacket) and I want to practice by implementing a map function (apply a function to all elements of a list), but there's something wrong that I don't understand.
(I have, aside from my imperative background, a basic knowledge of haskell)
I want to translate the following piece of haskell (Just to show the algorithm) :
map f [] = []
map f x:xs = (f x) : (map f xs)
Here's my code :
(define (map f xs)
(if (= xs '()) '() ; if list is empty, return empty list
(cons (f (car xs)) (map f (cdr xs))))
)
To test it, I used this :
(define (testFunction x) (+ x 1))
(define testList '(1 2 3 4 5))
(map testFunction testList)
And I get the following error :
=: contract violation
expected: number ?
given : '(1 2 3 4 5)
argument position: 1st
other arguments...:
which highlights the predicate (= xs '())
Any tips ?

The = function is specifically for equality between numbers. It has special handling for numeric values by handling comparisons between exact and inexact numbers. In general, though, for non-numeric equality, you should use the equal? predicate:
> (equal? '() '())
#t
In this particular case, as mentioned by Raghav, you can also use empty? or null? to test for the empty list (the empty? predicate is just an alias for null?).

Wow - a few others already beat me to it, but I'll share my answer, anyways.
Your issue stems from your use of = to test list emptiness.
From the = in the docs:
Returns #t if all of the arguments are numerically equal, #f
otherwise.
In order to get your program working, I'd suggest using equal? to test the two lists for equality or, better yet, use empty? or null? to test if xs is an empty list. (I hope you don't take offense, but I've also massaged the code into what's (arguably) more idiomatic Scheme).
(define (mymap f xs)
(if (empty? xs)
xs
(cons
(f (car xs))
(mymap f (cdr xs)))))
(define (test-function x) (+ x 1))
(define test-list (list 1 2 3 4))
(mymap test-function test-list)

If you're using DrRacket, then for that condition, simply use (empty?):
(if (empty? xs)
xs ; because xs is empty
...)

Related

How do non-binary foldl and foldr work in Racket?

I'm familiar with the underlying workings and differences of foldl and foldr over a single list. However, in Racket, you can use folds on multiple lists. For example, you can find the difference of elements in two lists by writing
; (mapMinus '(3 4) '(1 2)) => '(2 2)
(define (mapMinus lst0 lst1)
(foldl (λ (hd0 hd1 acc) (cons (- hd0 hd1) acc)) '() lst0 lst1))
How exactly do Racket's implementations of foldl and foldr work to handle multiple lists? The Racket source code for foldl is available on GitHub here, but I don't know Chez Scheme well enough to understand it.
A fold that operates over multiple lists simply applies its lambda element-wise on all of the lists, simultaneously. Perhaps a simplified implementation (with no error checking, etc.) of it will make things clearer; let's compare a standard implementation of foldr (which IMHO is slightly simpler to understand than foldl):
(define (foldr proc init lst)
(if (null? lst)
init
(proc (car lst)
(foldr proc init (cdr lst)))))
With an implementation that accepts multiple lists:
(define (foldr proc init . lst) ; lst is a list of lists
(if (null? (car lst)) ; all lists assumed to be of same length
init
; use apply because proc can have any number of args
(apply proc
; append, list are required for building the parameter list
; in the right way so it can be passed to (apply proc ...)
(append (map car lst)
; use apply again because it's a variadic procedure
(list (apply foldr proc init (map cdr lst)))))))
All the extra code in the multi-list version is for applying proc to multiple elements at the same time, getting the current element of each list (map car lst) and advancing over all the lists (map cdr lst).
Also the implementation needs to take into account that the procedure operates over a variable number of lists, assuming that the provided lambda receives the correct number of arguments (number of input lists + 1). It works as expected:
(foldr (lambda (e1 e2 acc)
(cons (list e1 e2) acc))
'()
'(1 2 3)
'(4 5 6))
=> '((1 4) (2 5) (3 6))
I think what you really are asking is how to create a variadic function in Scheme/Racket. The answer is given at https://docs.racket-lang.org/guide/define.html, but let me just give you a quick example:
(define (foo a b . xs)
(+ a b (length xs)))
would be equivalent to
def foo(a, b, *xs):
return a + b + len(xs)
in Python. xs here is a list value containing the rest of the arguments.
The second piece of puzzle is, how to apply a variadic function with a list value. For that, you can use apply. Read more at https://docs.racket-lang.org/guide/application.html#%28part._apply%29. Again, here's a quick example:
(define (foo a b c) (+ a b c))
(apply foo 1 '(2 3))
;; equivalent to (foo 1 2 3)
would be equivalent to
def foo(a, b, c): return a + b + c
foo(1, *[2, 3]) ;; equivalent to foo(1, 2, 3)
With these, creating a fold that accepts multiple arguments is just a programming exercise:
(define (my-fold proc accum required-first-list . list-of-optional-lists)
... IMPLEMENT FOLD HERE ...)
Note that if you read the source code of Racket (which uses Chez Scheme), you will see that it uses case-lambda instead of defining the function directly. case-lambda is just a way to make the code more efficient for common usage of fold (i.e., a fold with only one list).

Implementing sublist? using accumulate in Racket

I need to implement sublist? as a one-liner function that uses accumulate.
It is suppose to return true if set1 is in set2.
Something like this:
(define subset?
(lambda (set1 set2)
(accumulate member? (car set1) (lambda (x) x) set2)))
Honestly I think I'm just confused on how accumulate is suppose to work with member, or if member is even the right choice for the operator.
My accumulate function is:
(define accumulate
(lambda (op base func ls)
(if (null? ls)
base
(op (func (car ls))
(accumulate op base func (cdr ls))))))
and member?:
(define member?
(lambda (item ls)
(cond ((null? ls) #f)
((equal? item (car ls)) #t)
(else (member? item (cdr ls))))))
To give the correct definition of subset? first we must understand how the function accumulate works and the meaning of its parameters.
If we “unfold” the recursive definition, we can see that accumulate applies the binary operator op to all the results of applying func to the elements of list ls. And since the list can be empty, in these cases the function is defined to give back the value base.
So, for instance, assuming the recursive execution of the function, the following expression
(accumulate + 0 sqr '(1 2 3))
produces 14, since it is equivalent to:
(+ (sqr 1) (+ (sqr 2) (+ (sqr 3) 0)))
that is 1 + 4 + 9 + 0.
To solve your problem, you have to define a call to accumulate that applies the same operator to a list of elements and then combine the results. In you case, the operation to be applied is a test if an element is member of a list (member?), and you can apply it to all the elements of set1. And you should know, from the definition of the subset, that a set s1 is subset of another set s2 if and only if all the elements of s1 are contained in s2. So the operator that must be applied to combine all the results of the test is just the and boolean operator, so that it will be true if all the elements of s1 are member of s2 and false otherwise. The last thing to decide is the base value: this should be true, since an empty set is always contained in another set.
So this is a possible definition of subset?:
(define (subset? set1 set2)
(accumulate
(lambda (x y) (and x y)) ;; the combination operator
#t ;; the value for the empty list
(lambda(x) (member x set2)) ;; the function to be applied to all the elements of
set1)) ;; the set set1

How to reverse the order of elements of a list in Scheme

I got a function to reverse the order of the elements in a list, such as
(define (rvsl sequence)
(foldl (lambda (x y)
(cons y x))
'() sequence))
However, when I ran it in DrRacket with the input
(rvsl (list 2 3 4))
DrRacket told me this
cons: second argument must be a list, but received empty and 2
Could anybody please give me some ideas to solve it?
Thanks in advance!
The problem with your code is that you're passing the parameters in the wrong order - when using cons to build a list, the first parameter is the new element we want to stick at the beginning of the list, and the second one is the list we've built so far.
Having said that, reversing a list using foldl is a bit simpler and you don't need to use append at all - in fact, it's a bad practice using append when cons suffices:
(define (rvsl sequence)
(foldl cons
'()
sequence))
Why this works? let's rewrite the function being more explicit this time:
(define (rvsl sequence)
(foldl (lambda (current accumulated)
(cons current accumulated))
'()
sequence))
Now we can see that the lambda procedure receives two parameters: the current element in the input list, and the accumulated value so far - good parameter names make all the difference in the world! this is much, much clearer than calling the parameters x and y, which says nothing about them.
In this case, we just want to cons the current element at the head of the accumulated value (which starts as an empty list), hence producing a reversed list as the output. Given that the lambda procedure receives two parameters and passes them in the same order to cons, we can simplify the whole thing and just pass the cons procedure as a parameter.
Here is a simple version, using an internal iterative procedure.
(define (rev lst)
(define (iter accum lst)
(if (null? lst)
accum
(iter (cons (car lst) accum)
(cdr lst))))
(iter '() lst))
You don't have to use foldl or anything else, actually, to define the rev function; the rev function itself is enough:
(define (rev ls) ; rev [] = []
(cond ; rev [x] = [x]
((null? ls) ls) ; rev (x:xs)
((null? (rest ls)) ls) ; | (a:b) <- rev xs
(else ; = a : rev (x : rev b)
(cons (first (rev (rest ls)))
(rev (cons (first ls)
(rev (rest (rev (rest ls))))))))))
(comments in equational pattern-matching pseudocode). Derivation and some discussion here.
(edit: that's obviously a toy code, just to hone your Scheme-fu).

List length in scheme

Hi I am trying to write a program where given a list of lists check to see if they are equal in size and return #t if they are.
So for example if i were to write (list-counter? '((1 2 3) (4 5 6) (7 8 9))) the program would return #t, and (list-counter? '((1 2 3) (4 5 6) (7 8))) would return #f.
SO far this is what I have done:
(define list-counter?
(lambda (x)
(if (list? x)
(if (list?(car x))
(let (l (length (car x))))
(if (equal? l (length(car x))))
(list-counter?(cdr x))
) ) ) ) )
I think where I am going wrong is after I set the length of l to the length of the first list. Any help would be appreciated.
There are several ways to solve this problem. For instance, by hand and going step-by-step:
(define (all-lengths lists)
(if (null? lists)
'()
(cons (length (car lists))
(all-lengths (cdr lists)))))
(define (all-equal? head lengths)
(if (null? lengths)
true
(and (= head (car lengths))
(all-equal? head (cdr lengths)))))
(define (list-counter? lists)
(let ((lengths (all-lengths lists)))
(all-equal? (car lengths) (cdr lengths))))
Let me explain the above procedures. I'm dividing the problem in two steps, first create a new list with the lengths of each sublist - that's what all-lengths does. Then, compare the first element in a list with the rest of the elements, and see if they're all equal - that's what all-equal? does. Finally, list-counter? wraps it all together, calling both of the previous procedures with the right parameters.
Or even simpler (and shorter), by using list procedures (higher-order procedures):
(define (list-counter? lists)
(apply = (map length lists)))
For understanding the second solution, observe that all-lengths and all-equal? represent special cases of more general procedures. When we need to create a new list with the result of applying a procedure to each of the elements of another list, we use map. And when we need to apply a procedure (= in this case) to all of the elements of a list at the same time, we use apply. And that's exactly what the second version of list-counter? is doing.
You could write an all-equal? function like so:
(define (all-equal? list)
;; (all-equal? '()) -> #t
;; (all-equal? '(35)) -> #t
;; (all-equal? '(2 3 2)) -> #f
(if (or (null? list) (null? (cdr list)))
#t
(reduce equal? list)
))
then do:
(all-equal? (map length listOfLists))
Alternatively you can do:
(define (lists-same-size? list-of-lists)
(if (== (length listOfLists) 0)
#t
(let*
(( firstLength
(length (car listOfLists)) )
( length-equal-to-first?
(lambda (x) (== (length x) firstLength)) )
)
(reduce and #t (map length-equal-to-first? listOfLists))
)
)))
What this says is: if the list length is 0, our statement is vacuously true, otherwise we capture the first element of the list's length (in the 'else' part of the if-clause), put it in the closure defined by let's syntactic sugar (actually a lambda), and use that to define an length-equal-to-first? function.
Unfortunately reduce is not lazy. What we'd really like is to avoid calculating lengths of lists if we find that just one is not equal. Thus to be more efficient we could do:
...
(let*
...
( all-match? ;; lazy
(lambda (pred list)
(if (null? list)
#t
(and (pred (first list)) (all-match? (cdr list)))
;;^^^^^^^^^^^^^^^^^^^ stops recursion if this is false
)) )
)
(all-match? length-equal-to-first? listOfLists)
)
)))
Note that all-match? is already effectively defined for you with MIT scheme's (list-search-positive list pred) or (for-all? list pred), or in Racket as andmap.
Why does it take so long to write?
You are forced to write a base-case because your reduction has no canonical element since it relies on the first element, and list manipulation in most languages is not very powerful. You'd even have the same issue in other languages like Python. In case this helps:
second method:
if len(listOfLists)==0:
return True
else:
firstLength = len(listOfLists[0])
return all(len(x)==firstLength for x in listOfLists)
However the first method is much simpler to write in any language, because it skirts this issue by ignoring the base-cases.
first method:
if len(listOfLists)<2:
return True
else:
return reduce(lambda a,b: a==b, listOfLists)
This might sound a bit weird, but I think it is easy.
Run down the list, building a new list containing the length of each (contained) list, i.e. map length.
Run down the constructed list of lengths, comparing the head to the rest, return #t if they are all the same as the head. Return false as soon as it fails to match the head.

Why list-ref can not got the correct parameter?

I wrote a quick-sort in scheme (racket)
#lang racket
(define (quick-sort xs)
(let* ([p (list-ref xs 0)]
[tail (list-tail xs 1)]
[less (filter (lambda (x) (< x p)) tail)]
[greater (filter (lambda (x) (>= x p)) tail)])
(append (quick-sort less) (list p) (quick-sort greater))))
But when I tried it I got this error:
> (quick-sort (list 99 2 9922))
list-ref: index 0 too large for list: '()
I'm new to scheme so I don't quite understand why list-ref can't get the correct input '(99 2 9922)
Edit:
Thanks. I made it work.
#lang racket
(define (quick-sort xs)
(let* ([p (first xs)]
[tail (rest xs)]
[less (filter (lambda (x) (< x p)) tail)]
[greater (filter (lambda (x) (>= x p)) tail)])
(if (equal? (length xs) 1)
xs
(append (quick-sort less) (list p) (quick-sort greater)))))
When designing a recursive algorithm, two things are crucial: your terminating condition and your recursive step, and you don't have a terminating condition. Trace what your code is doing: During your first execution of quick-sort, you'll call:
(append (quick-sort (list 2)) (list 99) (quick-sort (list 9922)))
And the first quick-sort call will in turn invoke (quick-sort '()). Your code doesn't handle the empty list very gracefully, as it will always try to reference the first element of the array as the first thing it does.
Add logic to gracefully handle the empty list.
Also, using first and rest to get the first and remaining elements of a list is considered to be much more pragmatic.
Your code is missing the base case, when the input list is empty. When that happens, list-ref fails with that error.
BTW, note that a better name for (list-ref l 0) is (first l), and similarly (list-tail l 1) is better written as (rest l).
(There's also car and cdr, but if you're a newbie you can ignore them for now.)
You probably already know this, but Racket comes with a built-in sort function too.

Resources