Scheme/Lisp nested loops and recursion - functional-programming

I'm trying to solve a problem in Scheme which is demanding me to use a nested loop or a nested recursion.
e.g. I have two lists which I have to check a condition on their Cartesian product.
What is the best way to approach these types of problems? Any pointers on how to simplify these types of functions?
I'll elaborate a bit, since my intent might not be clear enough.
A regular recursive function might look like this:
(define (factorial n)
(factorial-impl n 1))
(define (factorial-impl n t)
(if (eq? n 0)
t
(factorial-impl (- n 1) (* t n))))
Trying to write a similar function but with nested recursion introduces a new level of complexity to the code, and I was wondering what the basic pattern is for these types of functions, as it can get very ugly, very fast.
As a specific example, I'm looking for the easiest way to visit all the items in a cartesian product of two lists.

In Scheme,
The "map" function is often handy for computing one list based on another.
In fact, in scheme, map takes an "n-argument" function and "n" lists and calls the
function for each corresponding element of each list:
> (map * '(3 4 5) '(1 2 3))
(3 8 15)
But a very natural addition to this would be a "cartesian-map" function, which would call your "n-argument" function with all of the different ways of picking one element from each list. It took me a while to figure out exactly how to do it, but here you go:
; curry takes:
; * a p-argument function AND
; * n actual arguments,
; and returns a function requiring only (p-n) arguments
; where the first "n" arguments are already bound. A simple
; example
; (define add1 (curry + 1))
; (add1 3)
; => 4
; Many other languages implicitly "curry" whenever you call
; a function with not enough arguments.
(define curry
(lambda (f . c) (lambda x (apply f (append c x)))))
; take a list of tuples and an element, return another list
; with that element stitched on to each of the tuples:
; e.g.
; > (stitch '(1 2 3) 4)
; ((4 . 1) (4 . 2) (4 . 3))
(define stitch
(lambda (tuples element)
(map (curry cons element) tuples)))
; Flatten takes a list of lists and produces a single list
; e.g.
; > (flatten '((1 2) (3 4)))
; (1 2 3 4)
(define flatten
(curry apply append))
; cartesian takes two lists and returns their cartesian product
; e.g.
; > (cartesian '(1 2 3) '(4 5))
; ((1 . 4) (1 . 5) (2 . 4) (2 . 5) (3 . 4) (3 . 5))
(define cartesian
(lambda (l1 l2)
(flatten (map (curry stitch l2) l1))))
; cartesian-lists takes a list of lists
; and returns a single list containing the cartesian product of all of the lists.
; We start with a list containing a single 'nil', so that we create a
; "list of lists" rather than a list of "tuples".
; The other interesting function we use here is "fold-right" (sometimes called
; "foldr" or "reduce" in other implementations). It can be used
; to collapse a list from right to left using some binary operation and an
; initial value.
; e.g.
; (fold-right cons '() '(1 2 3))
; is equivalent to
; ((cons 1 (cons 2 (cons 3 '())))
; In our case, we have a list of lists, and our binary operation is to get the
; "cartesian product" between each list.
(define cartesian-lists
(lambda (lists)
(fold-right cartesian '(()) lists)))
; cartesian-map takes a n-argument function and n lists
; and returns a single list containing the result of calling that
; n-argument function for each combination of elements in the list:
; > (cartesian-map list '(a b) '(c d e) '(f g))
; ((a c f) (a c g) (a d f) (a d g) (a e f) (a e g) (b c f)
; (b c g) (b d f) (b d g) (b e f) (b e g))
(define cartesian-map
(lambda (f . lists)
(map (curry apply f) (cartesian-lists lists))))
Without all the comments and some more compact function definition syntax we have:
(define (curry f . c) (lambda x (apply f (append c x))))
(define (stitch tuples element)
(map (curry cons element) tuples))
(define flatten (curry apply append))
(define (cartesian l1 l2)
(flatten (map (curry stitch l2) l1)))
(define cartesian-lists (curry fold-right cartesian '(()))))
(define (cartesian-map f . lists)
(map (curry apply f) (cartesian-lists lists)))
I thought the above was reasonably "elegant"... until someone showed me the equivalent Haskell definition:
cartes f (a:b:[]) = [ f x y | x <- a , y <- b ]
cartes f (a:b:bs) = cartes f ([ f x y | x <- a , y <- b ]:bs)
2 lines!!!
I am not so confident on the efficiency of my implementation - particularly the "flatten" step was quick to write but could end up calling "append"
with a very large number of lists, which may or may not be very efficient on some Scheme
implementations.
For ultimate practicality/usefulness you would want a version that could take "lazily evaluated" lists/streams/iterator rather than fully specified lists.... a "cartesian-map-stream" function if you like, that would then return a "stream" of the results... but this depends on the context (I am thinking of the "stream" concept as introduced in SICP)... and would come for free from the Haskell version thanks to it's lazy evaluation.
In general, in Scheme, if you wanted to "break out" of the looping at some point you could also use a continuation (like throwing an exception but it is accepted practise in Scheme for control flow).
I had fun writing this!

I'm not sure I see what the problem is.
I believe the main thing you have to understand in functional programming is : build complicated functions by composing several simpler functions.
For instance, in this case:
;compute the list of the (x,y) for y in l
(define (pairs x l)
(define (aux accu x l)
(if (null? l)
accu
(let ((y (car l))
(tail (cdr l)))
(aux (cons (cons x y) accu) x tail))))
(aux '() x l))
(define (cartesian-product l m)
(define (aux accu l)
(if (null? l)
accu
(let ((x (car l))
(tail (cdr l)))
(aux (append (pairs x m) accu) tail))))
(aux '() l))
You identify the different steps: to get the cartesian product, if you "loop" over the first list, you're going to have to be able to compute the list of the (x,y), for y in the second list.

There are some good answers here already, but for simple nested functions (like your tail-recursive factorial), I prefer a named let:
(define factorial
(lambda (n)
(let factorial-impl ([n n] [t 1])
(if (eq? n 0)
t
(factorial-impl (- n 1) (* t n))))))

Related

Counting number of occurrences of elements in a list

I am writing a function called count-if, which takes in a predicate, p?, and a list, ls. The function returns the number of occurrences of elements in the nested list that satisfy p?
For example: (count-if (lambda (x) (eq? 'z x)) '((f x) z (((z x c v z) (y))))) will return 3. This is what I have written:
(define (count-if p ls) (cond
((null? ls) '())
((p (car ls))
(+ 1 (count-if p (cdr ls))))
(else
(count-if p (cdr ls)))))
But I just get an error. I could use some help finding a better way to go about this problem. Thanks!
What is the signature of count-if? It is:
[X] [X -> Boolean] [List-of X] -> Number
What does the first cond clause return? It returns:
'()
This is a simple type error. Just change the base case to 0 and count-if works.
Edit (for nested).
First we define the structure of the date as Nested.
A symbol is just fed into the score helper function. Otherwise the recursive call is applied on all nested sub-nesteds, and the results are summed up.
#lang racket
; Nested is one of:
; - Number
; - [List-of Nested]
; Nested -> Number
(define (count-if pred inp)
; Symbol -> Number
(define (score n) (if (pred n) 1 0))
; Nested -> Number
(define (count-if-h inp)
(if (symbol? inp)
(score inp)
(apply + (map count-if-h inp))))
(count-if-h inp))
(count-if (lambda (x) (eq? 'z x)) '((f x) z (((z x c v z) (y)))))
; => 3

Racket, writing function that find nth element in list

In order to understand functional programing, please help me to write a function that output nth element of a list,
Allowed command:
define lambda cond else empty empty? first rest cons list
list? = equal? and or not + - * / < <= > >=
Sample output:
(fourth-element '(a b c d e)) => d
(fourth-element '(x (y z) w h j)) => h
(fourth-element '((a b) (c d) (e f) (g h) (i j))) => (list 'g 'h)
or ‘(g h)
(fourth-element '(a b c)) => empty
I could write this in python, but I am not family with racket syntax,
def element(lst, x=0):
counter = x;
if (counter >= 3):
return lst[0]
else:
return element(lst[1:],x+1)
a = [1,2,3,4,5,6]
print(element(a))
The Output is 4
Comparing with code above in python. What is equivalent behavior in function that create local variable counter. What is "keyword" for return
It looks like you came up with an answer of your own. Nice work! I would recommend a more generic nth procedure that takes a counter as an argument. This allows you to get any element in the input list
(define (nth lst counter)
(cond ((null? lst) (error 'nth "index out of bounds"))
((= counter 0) (first lst))
(else (nth (rest lst) (- counter 1)))))
Now if you want a procedure that only returns the 4th element, we create a new procedure which specializes the generic nth
(define (fourth-element lst)
(nth lst 3))
That's it. Now we test them out with your inputs
(define a `(1 2 3 (4 5) 7))
(define b `(1 2 3))
(define c `((a b)(c d)(e f)(g h)(i j)))
(define d `(a b c))
(fourth-element a) ; '(4 5)
(fourth-element b) ; nth: index out of bounds
(fourth-element c) ; '(g h)
(fourth-element d) ; nth: index out of bounds
Note, when the counter goes out of bounds, I chose to raise an error instead of returning a value ("empty") like your program does. Returning a value makes it impossible to know whether you actually found a value in the list, or if the default was returned. In the example below, notice how your procedure cannot differentiate the two inputs
(define d `(a b c))
(define e `(a b c ,"empty"))
; your implementation
(fourth-element e) ; "empty"
(fourth-element d) ; "empty"
; my implementation
(fourth-element e) ; "empty"
(fourth-element d) ; error: nth: index out of bounds
If you don't want to throw an error, there's another way we can encode nth. Instead of returning nth element, we can return the nth pair whose head contains the element in question.
Below, nth always returns a list. If the list is empty, no element was found. Otherwise, the nth element is the first element in the result.
(define (nth lst counter)
(cond ((null? lst) '())
((= counter 0) lst)
(else (nth (rest lst) (- counter 1)))))
(define (fourth-element lst)
(nth lst 3))
(define a `(1 2 3 (4 5) 7))
(define b `(1 2 3))
(define c `((a b)(c d)(e f)(g h)(i j)))
(define d `(a b c))
(define e `(a b c ,"empty"))
(fourth-element a) ; '((4 5) 7)
(fourth-element b) ; '()
(fourth-element c) ; '((g h) (i j))
(fourth-element d) ; '()
(fourth-element e) ; '("empty")
Hopefully this gets you to start thinking about domain (procedure input type) and codomain (procedure output type).
In general, you want to design procedures that have natural descriptions like:
" nth takes a list and a number and always returns a list" (best)
" nth takes a list and a number and returns an element of the list or raises an exception if the element is not found" (good, but now you must handle errors)
Avoid procedures like
" nth takes a list and a number and returns an element of the list or a string literal "empty" if the element is not found" (unclear codomain)
By thinking about your procedure's domain and codomain, you have awareness of how your function will work as it's inserted in various parts of your program. Using many procedures with poorly-defined domains lead to disastrous spaghetti code. Conversely, well-defined procedures can be assembled like building blocks with little (or no) glue code necessary.
Here is how to write it in Python:
def nth(lst, idx=0):
if (len(lst) == 0):
return "empty"
elif (idx == 0):
return lst[0]
else:
return nth(lst[1:], idx - 1)
nth([1,2,3], 1)
# ==> 2
def fourth-element(lst):
return nth(lst, 4)
Same in Scheme/Racket:
(define (nth lst idx)
(cond ((empty? lst) empty) ; more effiecent than (= (length lst) 0)
((= idx 0) (first lst))
(else (nth (rest lst) (- idx 1))))
(nth '(1 2 3) 1)
; ==> 2
(define (fourth-element lst)
(nth lst 4))
There is no keyword for return. Every form returns the last evaluated code:
(if (< 4 x)
(bar x)
(begin
(display "print this")
(foo x)))
This if returns either the result of (bar x) or it prints "print this" then returns the result of (foo x). The reason is that for the two outcomes of the if they are the tail expressions.
(define (test x)
(+ x 5)
(- x 3))
This function has two expressions. The first is dead code since it has no side effect and since it's not a tail expression, but the (- x 3) is what this function returns.
(define (test x y)
(define xs (square x))
(define ys (square y))
(sqrt (+ xs ys)))
This has 3 expressions. The first two has side effects that it binds two local variables while the third uses this to compute the returned value.
(define a `(1 2 3 (4 5) 7))
(define b `(1 2 3))
(define c `((a b)(c d)(e f)(g h)(i j)))
(define d `(a b c))
(define (my-lst-ref lst counter)
(cond[(>= counter 3) (first lst)]
[else (my-lst-ref (rest lst)(+ counter 1))]
)
)
(define (fourth-element lst)
(cond[(>= (list-length lst) 4) (my-lst-ref lst 0)]
[else "empty"]))
(fourth-element a)
(fourth-element c)
(fourth-element d)
Output:
(list 4 5)
(list 'g 'h)
"empty"

Scheme Make list of all pair permutations of elements in two equal length lists

I am trying to combine two lists of x coordinates and y coordinates into pairs in scheme, and I am close, but can't get a list of pairs returned.
The following can match up all the pairs using nested loops, but I'm not sure the best way to out put them, right now I am just displaying them to console.
(define X (list 1 2 3 4 5))
(define Y (list 6 7 8 9 10))
(define (map2d X Y)
(do ((a 0 (+ a 1))) ; Count a upwards from 0
((= a (length X) ) ) ; Stop when a = length of list
(do ((b 0 (+ b 1))) ; Count b upwards from 0
((= b (length Y) ) ) ; Stop when b = length of second list
(display (cons (list-ref X a) (list-ref Y b))) (newline)
))
)
(map2d X Y)
I am looking to have this function output
((1 . 6) (1 . 7) (1 . 8) ... (2 . 6) (2 . 7) ... (5 . 10))
I will then use map to feed this list into another function that takes pairs.
Bonus points if you can help me make this more recursive (do isn't 'pure' functional, right?), this is my first time using functional programming and the recursion has not been easy to grasp. Thanks!
The solutions of Óscar López are correct and elegant, and address you to the “right” way of programming in a functional language. However, since you are starting to study recursion, I will propose a simple recursive solution, without high-level functions:
(define (prepend-to-all value y)
(if (null? y)
'()
(cons (cons value (car y)) (prepend-to-all value (cdr y)))))
(define (map2d x y)
(if (null? x)
'()
(append (prepend-to-all (car x) y) (map2d (cdr x) y))))
The function map2d recurs on the first list: if it is empty, then the cartesian product will be empty; otherwise, it will collect all the pairs obtained by prepending the first element of x to all the elements of y, with all the pairs obtained by applying itself to the rest of x and all the elements of y.
The function prepend-to-all, will produce all the pairs built from a single value, value and all the elements of the list y. It recurs on the second parameter, the list. When y is empty the result is the empty list of pairs, otherwise, it builds a pair with value and the first element of y, and “conses” it on the result of prepending value to all the remaining elements of y.
When you will master the recursion, you can pass to the next step, by learning tail-recursion, in which the call to the function is not contained in some other “building” form, but is the first one of the recursive call. Such form has the advantage that the compiler can transform it into a (much) more efficient iterative program. Here is an example of this technique applied to your problem:
(define (map2d x y)
(define (prepend-to-all value y pairs)
(if (null? y)
pairs
(prepend-to-all value (cdr y) (cons (cons value (car y)) pairs))))
(define (cross-product x y all-pairs)
(if (null? x)
(reverse all-pairs)
(cross-product (cdr x) y (prepend-to-all (car x) y all-pairs))))
(cross-product x y '()))
The key idea is to define an helper function with a new parameter that “accumulates” the result while it is built. This “accumulator”, which is initialized with () in the call of the helper function, will be returned as result in the terminal case of the recursion. In this case the situation is more complex since there are two functions, but you can study the new version of prepend-to-all to see how this works. Note that, to return all the pairs in the natural order, at the end of the cross-product function the result is reversed. If you do not need this order, you can omit the reverse to make the function more efficient.
Using do isn't very idiomatic. You can try nesting maps instead, this is more in the spirit of Scheme - using built-in higher-order procedures is the way to go!
; this is required to flatten the list
(define (flatmap proc seq)
(fold-right append '() (map proc seq)))
(define (map2d X Y)
(flatmap
(lambda (i)
(map (lambda (j)
(cons i j))
Y))
X))
It's a shame you're not using Racket, this would have been nicer:
(define (map2d X Y)
(for*/list ([i X] [j Y])
(cons i j)))

Dr. Racket Recursion count occurrences

I'm new to Racket and trying to learn it. I'm working through some problems that I'm struggling with. Here is what the problem is asking:
Write a definition for the recursive function occur that takes a data expression a and a list s and returns the number of times that the data expression a appears in the list s.
Example:
(occur '() '(1 () 2 () () 3)) =>3
(occur 1 '(1 2 1 ((3 1)) 4 1)) => 3 (note that it only looks at whole elements in the list)
(occur '((2)) '(1 ((2)) 3)) => 1
This is what I have written so far:
(define occur
(lambda (a s)
(cond
((equal? a (first s))
(else (occur a(rest s))))))
I'm not sure how to implement the count. The next problem is similar and I have no idea how to approach that. Here is what this problem says:
(This is similar to the function above, but it looks inside the sublists as well) Write a recursive function atom-occur?, which takes two inputs, an atom a and a list s, and outputs the Boolean true if and only if a appears somewhere within s, either as one of the data expressions in s, or as one of the data expression in one of the data expression in s, or…, and so on.
Example:
(atom-occur? 'a '((x y (p q (a b) r)) z)) => #t
(atom-occur? 'm '(x (y p (1 a (b 4)) z))) => #f
Any assistance would be appreciated. Thank you.
In Racket, the standard way to solve this problem would be to use built-in procedures:
(define occur
(lambda (a s)
(count (curry equal? a) s)))
But of course, you want to implement it from scratch. Don't forget the base case (empty list), and remember to add one unit whenever a new match is found. Try this:
(define occur
(lambda (a s)
(cond
((empty? s) 0)
((equal? a (first s))
(add1 (occur a (rest s))))
(else (occur a (rest s))))))
The second problem is similar, but it uses the standard template for traversing a list of lists, where we go down on the recursion on both the first and the rest of the input list, and only test for equality when we're in an atom:
(define atom-occur?
(lambda (a s)
(cond
((empty? s) #f)
((not (pair? s))
(equal? a s))
(else (or (atom-occur? a (first s))
(atom-occur? a (rest s)))))))

Racket/Scheme Flatten Explanations

Can someone help me to break down exactly the order of execution for the following versions of flatten? I'm using Racket.
version 1, is from racket itself, while version two is a more common? implementation.
(define (flatten1 list)
(let loop ([l list] [acc null])
(printf "l = ~a acc = ~a\n" l acc)
(cond [(null? l) acc]
[(pair? l) (loop (car l) (loop (cdr l) acc))]
[else (cons l acc)])))
(define (flatten2 l)
(printf "l = ~a\n" l)
(cond [(null? l) null]
[(atom? l) (list l)]
[else (append (flatten2 (car l)) (flatten2 (cdr l)))]))
Now, running the first example with '(1 2 3) produces:
l = (1 2 3) acc = ()
l = (2 3) acc = ()
l = (3) acc = ()
l = () acc = ()
l = 3 acc = ()
l = 2 acc = (3)
l = 1 acc = (2 3)
'(1 2 3)
while the second produces:
l = (1 2 3)
l = 1
l = (2 3)
l = 2
l = (3)
l = 3
l = ()
'(1 2 3)
The order of execution seems different. In the first example, it looks like the second loop (loop (cdr l) acc) is firing before the first loop since '(2 3) is printing right away. Whereas in the second example, 1 prints before the '(2 3), which seems like the first call to flatten inside of append is evaluated first.
I'm going through the Little Schemer but these are more difficult examples that I could really use some help on.
Thanks a lot.
Not really an answer to your question (Chris provided an excellent answer already!), but for completeness' sake here's yet another way to implement flatten, similar to flatten2 but a bit more concise:
(define (atom? x)
(and (not (null? x))
(not (pair? x))))
(define (flatten lst)
(if (atom? lst)
(list lst)
(apply append (map flatten lst))))
And another way to implement the left-fold version (with more in common to flatten1), using standard Racket procedures:
(define (flatten lst)
(define (loop lst acc)
(if (atom? lst)
(cons lst acc)
(foldl loop acc lst)))
(reverse (loop lst '())))
The main difference is this:
flatten1 works by storing the output elements (first from the cdr side, then from the car side) into an accumulator. This works because lists are built from right to left, so working on the cdr side first is correct.
flatten2 works by recursively flattening the car and cdr sides, then appending them together.
flatten1 is faster, especially if the tree is heavy on the car side: the use of an accumulator means that there is no extra list copying, no matter what. Whereas, the append call in flatten2 causes the left-hand side of the append to be copied, which means lots of extra list copying if the tree is heavy on the car side.
So in summary, I would consider flatten2 a beginner's implementation of flatten, and flatten1 a more polished, professional version. See also my implementation of flatten, which works using the same principles as flatten1, but using a left-fold instead of the right-fold that flatten1 uses.
(A left-fold solution uses less stack space but potentially more heap space. A right-fold solution uses more stack and usually less heap, though a quick read of flatten1 suggests in this case that the heap usage is about the same as my implementation.)

Resources