Idiomatic usage of local vs lambda? - scheme

In Exercise 30.1.1 of HtDP, I started off using local and then modified it to use lambda in order to answer the question.
(define (add-to-each2 accu a-list)
(cond
[(empty? a-list) empty]
[else (local ((define s (+ accu (first a-list))))
(cons s (add-to-each2 s (rest a-list))))]))
and
(define (add-to-each5 accu a-list)
(cond
[(empty? a-list) empty]
[else (cons ((lambda (x y)
(first (map + (list (first y))
(list x)))) accu a-list)
(add-to-each5 (+ accu (first a-list))(rest a-list)))]))
In this particular instance, to me, the local version is easier to read. Are there situations where the lambda version would be preferred? Thank you.

First off, I think you might be getting relative-2-absolute confused with add-to-each, since add-to-each just adds the same number to each element of the list, rather than incrementing an accumulator. The rest of this post assumes that's the case, and just takes out that incrementing.
I think let would be my first choice for the local binding. Your lambda example uses a common pattern that simulates let using lambda and application:
(let ([x e]) body)
Is equivalent to:
((lambda (x) body) e)
If you use this transformation from lambda to let in your example, you get:
(define (add-to-each5 n a-list)
(cond
[(empty? a-list) empty]
[else (cons (let ([x n] [y a-list])
(first (map + (list (first y))
(list x))))
(add-to-each5 n (rest a-list)))]))
A good compiler will likely generate the same code for this as for your two examples, so it mostly comes down to style. The "left-left lambda" pattern can be more difficult to read, as you note, so I prefer let.
However, Exercise 30.1.1 is trying to make you use map as a replacement for the explicit recursion that occurs in each of your examples. You are using map in your example but only for a single addition at a time, which makes map kind of painful: why bother wrapping up (list (first y)) and (list x) when you just want (+ (first y) x)?
Let's look at a simple definition of map to see how it might be helpful, rather than painful, for this problem:
(define (map f ls)
(cond
[(empty? ls) empty]
[else (cons (f (first ls)) (map f (rest ls)))]))
Right away, you should notice some similarities to add-to-each: the first line of the cond checks for empty, and the second line conses something to do with the first element onto a recursive call to map on the rest. The key, then, is to pass map an f that does what you want to do to each element.
In the case of add-to-each, you want to add a particular number to each element. Here's an example of adding 2:
> (map (lambda (n) (+ 2 n)) (list 1 2 3 4 5))
(3 4 5 6 7)
Notice that map and lambda are both here as 30.1.1 requests, and they act on an entire list without the explicit recursion of the original add-to-each: the recursion is all abstracted away in map.
This should be enough to get you to a solution; I don't want to give away the final answer, though :)

Related

Need a hint on a homework question which asks to add numbers in a list in a particular way

This is a homework question
The function takes in a list as the parameter, which may contain as many layers as sublists as needed For example, '(a (1 b 3)) or '((a 3 5) (b (3 1) 4)). The output has the same list structure of the input (meaning that sublists are maintained), but the car of each list is the sum of all numbers in the list. And all other non-numeric values are discarded. As an example output, consider '((a 3 5) (b (3 1) 4)), the output should be '(16 (8) (8 (4))). Also, only use basic scheme instructions/operations such as + - * /, car, cdr, cons, append, null?, number?, if/else, cond, etc.. Cannot Use a helper method.
So far this is the code I have, which sometimes partially does the job. But I'm having a really hard time figuring out how to get the sum from the sublists to add up at one spot at the car of the outmost list.
(define partialsums*
(lambda (lis)
(cond
[(null? lis) '(0)]
[(list? (car lis)) (cons (partialsums* (car lis)) (if (not (null? (cdr lis))) (partialsums* (cdr lis)) '()))]
[(number? (car lis)) (cons (+ (car lis) (car (partialsums* (cdr lis)))) '())]
[else (cons (+ 0 (car (partialsums* (cdr lis)))) '())])))
I've already spent several hours on this but couldn't quite grasp how to correctly approach the problem, probably because this is my first week using scheme :(. Any help is appreciated.
Also, I cannot use a helper method. Everything needs to be done inside one function in a recursive style. letrec is not allowed either.
To make life easy, you should model the data. Since there are no types, we can do this informally.
What is the structure of the input?
We can model it like "Data Definitions" from How to Design Programs. Read the "Intertwined Data" section because our data definition is similar to that of an S-expression.
; A NestedElem is one of:
; - Atom
; - NestedList
; An Atom is one of:
; - Number
; - Symbol
; A NestedList is one of
; - '()
; - (cons NestedElem NestedList)
We can define an atom? predicate to help us differentiate between clauses of the kinds of data in our program.
; Any -> Boolean
; is `a` an atom?
(define atom?
(lambda (a)
(or (number? a)
(symbol? a))))
The structure of the program should match the structure of the Data.
So we define a "template" on our data. It distinguished and destructs each data into clauses. It further de-structures the rhs of a clause.
; NestedElem -> ...
(define nested-elem-template
(lambda (ne)
(cond
[(atom? ne) ...]
[else ...])))
; Atom -> ...
(define atom-template
(lambda (atom)
(cond [(number? atom) ...]
[(symbol? atom) ...])))
; NestedList -> ...
(define nested-list-template
(lambda (nl)
(cond [(null? nl) ...]
[else (... (car nl)... (cdr nl))])))
We definitely know more about the data. (car nl) in the nested-list-template is of type NestedElem. Therefore we can fill up some ...s with calls to templates that deal with that kind of data. In the same vein, we can wrap recursive calls around expressions of a datatype we know of.
; NestedElem -> ...
(define nested-elem-template
(lambda (ne)
(cond
[(atom? ne) (atom-template ne)]
[else (nested-list-template ne)])))
; Atom -> ...
(define atom-template
(lambda (atom)
(cond [(number? atom) ...]
[(symbol? atom) ...])))
; NestedList -> ...
(define nested-list-template
(lambda (nl)
(cond [(null? nl) ...]
[else (... (nested-elem-template (car nl))
... (nested-list-template (cdr nl)))])))
Now we can "fill in the blanks".
We can "filter", "map", and "fold" over this data structure. All those can be defined using the template as a scaffold.
Note 1: Your HW asks you to do multiple tasks:
remove the symbols
sum up the numbers
cons the sum onto every list
Don't try to do everything in a single function. Delegate into multiple helper functions/traversals.
Note 2: I did not model the output type. It's the same as input type except that Symbol is no longer an atom.

Product of squares of odd elements in list in Scheme

I wanted to write a code in Scheme that writes the square odd elements in list.For example (list 1 2 3 4 5) for this list it should write 225.For this purpose i write this code:
(define (square x)(* x x))
(define (product-of-square-of-odd-elements sequence)
(cond[(odd? (car sequence)) '() (product-of-square-of-odd-elements (cdr sequence))]
[else ((square (car sequence)) (product-of-square-of-odd-elements (cdr sequence)))]))
For run i write this (product-of-square-of-odd-elements (list 1 2 3 4 5))
and i get error like this:
car: contract violation
expected: pair?
given: '()
What should i do to make this code to run properly? Thank you for your answers.
First of all, you need to do proper formatting:
(define (square x) (* x x))
(define (product-of-square-of-odd-elements sequence)
(cond
[(odd? (car sequence))
'() (product-of-square-of-odd-elements (cdr sequence))]
[else
((square (car sequence)) (product-of-square-of-odd-elements (cdr sequence)))]))
Now there are multiple issues with your code:
You are trying to work recursively on a sequence, but you are missing a termination case: What happens when you pass '() - the empty sequence? This is the source of your error: You cannot access the first element of an empty sequence.
You need to build up your result somehow: Currently you're sending a '() into nirvana in the first branch of your cond and put a value into function call position in the second.
So let's start from scratch:
You process a sequence recursively, so you need to handle two cases:
(define (fn seq)
(if (null? seq)
;; termination case
;; recursive case
))
Let's take the recursive case first: You need to compute the square and multiply it with the rest of the squares (that you'll compute next).
(* (if (odd? (car seq)
(square (car seq))
1)
(fn (cdr seq)))
In the termination case you have no value to square. So you just use the unit value of multiplication: 1
This is not a good solution, as you can transform it into a tail recursive form and use higher order functions to abstract the recursion altogether. But I think that's enough for a start.
With transducers:
(define prod-square-odds
(let ((prod-square-odds
((compose (filtering odd?)
(mapping square)) *)))
(lambda (lst)
(foldl prod-square-odds 1 lst))))
(prod-square-odds '(1 2 3 4 5))
; ==> 225
It uses reusable transducers:
(define (mapping procedure)
(lambda (kons)
(lambda (e acc)
(kons (procedure e) acc))))
(define (filtering predicate?)
(lambda (kons)
(lambda (e acc)
(if (predicate? e)
(kons e acc)
acc))))
You can decompose the problem into, for example:
Skip the even elements
Square each element
take the product of the elements
With this, an implementation is naturally expressed using simpler functions (most of which exist in Scheme) as:
(define product-of-square-of-odd-elements (l)
(reduce * 1 (map square (skip-every-n 1 l))))
and then you implement a helper function or two, like skip-every-n.

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).

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.

double in scheme

How to write a program in scheme that takes an arbitrary
sexpression consisting of integers and which returns an sexpression that is identical to
the original but with all the integers doubled?
We want a procedure that takes an S-expression as input, and outputs an S-expression with the same structure, but where each integer is doubled; generally, a procedure to map S-expressions:
(define (double x)
(if (number? x)
(* x 2)
x)))
(define (sexp-map op sexp)
...)
(sexp-map double some-sexpression)
The S-expression we get (SEXP) is going to be either an atom, in which case the result is (OP SEXP), or a list of S-expressions. We might think to map OP across SEXP in this case, but S-expressions nest arbitrarily deep. What we should actually do is map a procedure that will transform each element in the smaller S-expression with OP. Well would you look at that, that's just another way to describe of the goal of the procedure we're currently trying to write. So we can map SEXP-MAP across SEXP.
Well, no we can't actually, because SEXP-MAP needs to be called with two arguments, and MAP will only give it the one. To get around that, we use a helper procedure F of one argument:
(define (sexp-map op sexp)
(define (f x)
(if (list? x)
(map f x)
(op x)))
(f sexp))
F winds up doing all the real work. SEXP-MAP is reduced to being a facade that's easier to use for the programmer.
It sounds like what you want is to find each integer in the s-expression, then double it, while keeping the rest of it the same.
If you're not aware, s-expressions are just lists that may happen to contain other lists, and it makes sense to deal with them in levels. For instance, here's a way to print all the values on level one of an s-expression:
(define (print-level-one sexp)
(display (car sexp))
(print-level-one (cdr sexp)))
This will end up calling display on the car of every part of the s-expression.
You could do something similar. You'll need the functions integer? and pair? to check whether something is an integer, which should be doubled, or another list, which should be treated just like the top-level list.
(Note: I'm being deliberately vague because of the comment about homework above. If you just want the answer, rather than help figuring out the answer, say so and I'll change this.)
An Sexp of numbers is one of
-- Number
-- ListOfSexp
A ListOfSexp is one of
-- empty
-- (cons Sexp ListOfSexp)
So, you'll need one function to handle both of those data definitions. Since the data definitions cross-reference each other, the functions will do the same. Each individual function is pretty straight forward.
(define (double E)
(cond ((null? E) '())
((list? (car E)) (cons (double (car E)) (double (cdr E))))
((number? E) (list E))
(else (cons (* 2 (car E)) (double (cdr E))))
))
(map (lambda (x) (* x 2)) '(1 2 3 4 5)) => '(2 4 6 8 10)
What does it do? (lambda (x) (* x 2)) takes a number and doubles it, and map applies that function to every element of a list.
Edit: Oh, but it won't go into trees.
(define double
(lambda (x)
(cond ((null? x) (list))
((list? (car x)) (cons (double (car x)) (double (cdr x))))
(else (cons (* 2 (car x)) (double (cdr x)))))))
EDIT
Fixed this. Thanks to Nathan Sanders for pointing out my initial oversight concerning nested lists.

Resources