Purely functional stack implementation with scheme - functional-programming

I would like to implement a functional stack in scheme.
This is my attempt:
(define make-stack
(letrec ((do-op
(lambda (stack op . val)
(cond ((eq? op 'push)
(lambda (op . v)
(do-op (cons (car val) stack) op v)))
((eq? op 'pop)
(lambda (op . v)
(do-op (cdr stack) op v)))
((eq? op 'print)
(begin (display stack)
(newline)
(lambda (op . v)
(do-op stack op v))))))))
(lambda (op . val)
(do-op '() op val))))
The stack can be used as in this example:
(define s make-stack)
((((((s 'push 1) 'push 2) 'push 3) 'print) 'pop) 'print)
The output of this example is:
((3) (2) (1))
((2) (1))
Not exactly what I wanted, but not too bad.
I wanted to ask the experienced schemers here if there is a way to make the stack behave more naturally, for example like this:
(define s make-stack)
(s 'push 1)
(s 'push 2)
(s 'pop)
...
while keeping it functional (so no mutability, no set!).
The first thing I thought was to keep returning a function with no arguments, but changing every lambda (op . v) with:
(lambda ()
(lambda (op . v)
...
but this does not work as we still need to capture the returned function:
> (define s make-stack)
> ((s) 'push 1)
#<procedure>

As Amalloy suggests, functional style has principles that contrast with your goal. It's not impossible to do something similar, however -
(define (run-stack s prgm)
(foldl (lambda (step s) (apply s step))
s
prgm))
(run-stack
make-stack
'((push 1)
(push 2)
(push 3)
(print)
(pop)
(print)))
To test this, I implemented make-stack as -
(define (dispatch-stack s)
(lambda payload
(match payload
((list 'pop)
(dispatch-stack (cdr s)))
((list 'push v)
(dispatch-stack (cons v s)))
((list 'print)
(println (reverse s))
(dispatch-stack s))
(_ (error "invalid stack operation" payload)))))
(define make-stack
(dispatch-stack null))
Output -
'(1 2 3)
'(1 2)
Another thing I think you would like to see is Make a language in one hour: stacker. This will help you to see how languages like Racket are fundamentally different from others you have probably worked with before.

Your goals are contradictory. If s is a stack, and your operations purely functional, then (s 'push 1) must return the same thing every time it is called. To capture the notion of change, you must use a different s each time. That's how your functional stack works: it gives you back a new stack, and you must compose function calls with it.

Related

Rewriting a common function using tail-end recursion

I've been trying to tinker with this code to rewrite a "repeat" function using tail-end recursion but have gotten a bit stuck in my attempts.
(define (repeat n x)
(if (= n 0)
'()
(cons x (repeat (- n 1) x))))
This is the original "repeat" function. It traverses through 'n - 1' levels of recursion then appends 'x' into a list in 'n' additional recursive calls. Instead of that, the recursive call should be made and the 'x' should be appended to a list at the same time.
(define (repeat-tco n x)
(trace-let rec ([i 0]
[acc '()])
(if (= i n)
acc
(rec (+ i 1) (cons x acc)))))
This is the closest rewritten version that I've come up with which I believe follows tail-call recursion but I'm not completely sure.
Your repeat-tco function is indeed tail recursive: it is so because the recursive call to rec is in 'tail position': at the point where it's called, the function that is calling it has nothing left to do but return the value of that call.
[The following is just some perhaps useful things: the answer is above, but an answer which was essentially 'yes' seemed too short.]
This trick of taking a procedure p which accumulates some result via, say (cons ... (p ...)) and turning it into a procedure with an extra 'accumulator' argument which is then tail recursive is very common. A result of using this technique is that the results come out backwards: this doesn't matter for you because all the elements of your list are the same, but imagine this:
(define (evens/backwards l)
(let loop ([lt l]
[es '()])
(if (null? lt)
es
(loop (rest lt)
(if (even? (first lt))
(cons (first lt) es)
es)))))
This will return the even elements of its arguments, but backwards. If you want them the right way around, a terrible answer is
(define (evens/terrible l)
(let loop ([lt l]
[es '()])
(if (null? lt)
es
(loop (rest lt)
(if (even? (first lt))
(append es (list (first lt)))
es)))))
(Why is it a terrible answer?) The proper answer is
(define (evens l)
(let loop ([lt l]
[es '()])
(if (null? lt)
(reverse es)
(loop (rest lt)
(if (even? (first lt))
(cons (first lt) es)
es)))))

Scheme error says "attempt to apply non-procedure" when flipping tuples in a list

I'm working through a textbook on programming languages, and one of the exercises was to make a function in Scheme that flips tuples in a list. Here's my code:
; invert : Listof(List(Int,Int)) -> Listof(List(Int,int))
; usage: (invert '((a 1) (a 2) (1 b) (2 b))) -> ((1 a) (2 a) (b 1) (b 2))
(define invert
(lambda (lst)
(if (null? lst)
'()
(cons
(flip (car lst))
(invert (cdr lst))))))
; flip : List(Int,Int) -> List(Int,int)
; usage: (flip '(a 1)) -> (1 a)
(define flip
(lambda (tuple)
(if (not (eqv? (length (tuple)) 2))
(eopl:error 'flip
"Tuple is not length 2~%")
(cons (cdr tuple) (car tuple)))))
I tried testing my program in chez-scheme. When I use the test case in the usage comment, I get this error: Exception: attempt to apply non-procedure (a 1). I've never worked with Scheme before, so I'd greatly appreciate any help and advice. Thanks!
You have a coupe of errors in flip, this should fix them:
(define flip
(lambda (tuple)
(if (not (= (length tuple) 2))
(eopl:error 'flip "Tuple is not length 2~%")
(list (cadr tuple) (car tuple)))))
In particular:
The specific error reported was because of this expression: (tuple). We must not surround variables with (), unless they're procedures that we intend to call.
We should use = for comparing numbers, not eqv?.
In this expression: (cons (cdr tuple) (car tuple)) there are two issues, for building a list of two elements we use list, not cons. And for accessing the second element we use cadr, not cdr - you should read a bit about how cons, car and cdr are used for building lists.
Notice that there's a simpler way to solve this problem if we use map; I'll skip error checking for simplicity:
(define (invert lst)
(map (lambda (tuple) (list (cadr tuple) (car tuple)))
lst))

Clisp : select sublists with a given length

Working on CLISP in Sublime Text.
Exp. in CLISP : less than 1 year
It's already for a while that I'm trying to solve this exercice... without success... as you might guess.
In fact I have to create a function which will modify the list and keeps only sublists which are equals or greater than the given number (watch below)
The list on which I have to work :
(setq liste '((a b) c (d) (e f) (e g x) f))
I'm supposed to find this as result :
(lenght 2 liste) => ((a b) (e f) (e g x))
liste => ((a b) (e f) (e g x))
Here my code :
(defun lenght(number liste)
(cond
((atom liste) nil)
((listp (car liste))
(rplacd liste (lenght number (cdr liste))) )
((<= (lenght number (car liste)) number)
(I don't know what to write) )
((lenght number (cdr liste))) ) )
It will be very kind if you could give me only some clue so as to let me find the good result.
Thanks guys.
Modifying the list does not make much sense, because it gets hairy at the head of the list to retain the original reference. Return a new list.
This is a filtering operation. The usual operator in Common Lisp for that is remove-if-not (or remove-if, or remove, depending on the condition). It takes a predicate that should return whether the element should be kept. In this case, it seems to be (lambda (element) (and (listp element) (>= (length element) minlength))).
(defun filter-by-min-length (minlength list)
(remove-if-not (lambda (element)
(and (listp element)
(>= (length element) minlength)))
list))
In many cases, when the condition is known at compile time, loop produces faster compiled code:
(defun filter-by-min-length (minlength list)
(loop :for element :in list
:when (and (listp element)
(>= (length element) minlength))
:collect element))
This returns a new list that fulfills the condition. You'd call it like (let ((minlength-list (filter-by-min-length 2 raw-list))) …).
Many basic courses insist on recursively using primitive operations on cons cells for teaching purposes at first.
The first attempt usually disregards the possible stack exhaustion. At each step, you first look whether you're at the end (then return nil), whether the first element should be discarded (then return the result of recursing on the rest), or if it should be kept (then cons it to the recursion result).
If tail call optimization is available, you can refactor this to use an accumulator. At each step, instead of first recursing and then consing, you cons a kept value onto the accumulator and pass it to the recursion. At the end, you do not return nil, but reverse the accumulator and return that.
Well, I have found the answer that I was looking for, after scratching my head until blood...
Seriously, here is the solution which is working (and thanks for the correction about length which helped me to find the solution ^^) :
(defun filter-by-min-length (min-length liste)
(cond
((atom liste) nil)
((and (listp (car liste))(>= (length (car liste)) min-length))
(rplacd liste (filter-by-min-length min-length (cdr liste))) )
((filter-by-min-length min-length (cdr liste))) ) )
A non-modifying version
(defun filter-by-min-length (min-length le)
(cond ((atom le) nil)
((and (listp (car le)) (>= (length (car le)) min-length))
(cons (car le) (filter-by-min-length min-length (cdr le))))
(t (filter-by-min-length min-length (cdr le)))))
Test:
(defparameter *liste* '((a b) c (d) (e f) (e g x) f))
(filter-by-min-length 2 *liste*)
;; ((A B) (E F) (E G X))
*liste*
;; ((A B) C (D) (E F) (E G X) F) ; -> *liste* not modified
For building good habits, I would recommend to use defparameter instead of setq, since the behaviour of setq might not always be defined (see here). In the link, it is said:
use defvar, defparameter, or let to introduce new variables. Use setf
and setq to mutate existing variables. Using them to introduce new
variables is undefined behaviour

What is "named let" and how do I use it to implement a map function?

I'm totally new to Scheme and I am trying to implement my own map function. I've tried to find it online, however all the questions I encountered were about some complex versions of map function (such as mapping functions that take two lists as an input).
The best answer I've managed to find is here: (For-each and map in Scheme). Here is the code from this question:
(define (map func lst)
(let recur ((rest lst))
(if (null? rest)
'()
(cons (func (car rest)) (recur (cdr rest))))))
It doesn't solve my problem though because of the usage of an obscure function recur. It doesn't make sense to me.
My code looks like this:
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
I do understand the logic behind the functional approach when programming in this language, however I've been having great difficulties with coding it.
The first code snippet you posted is indeed one way to implement the map function. It uses a named let. See my comment on an URL on how it works. It basically is an abstraction over a recursive function. If you were to write a function that prints all numbers from 10 to 0 you could write it liks this
(define (printer x)
(display x)
(if (> x 0)
(printer (- x 1))))
and then call it:
(printer 10)
But, since its just a loop you could write it using a named let:
(let loop ((x 10))
(display x)
(if (> x 0)
(loop (- x 1))))
This named let is, as Alexis King pointed out, syntactic sugar for a lambda that is immediately called. The above construct is equivalent to the snippet shown below.
(letrec ((loop (lambda (x)
(display x)
(if (> x 0)
(loop (- x 1))))))
(loop 10))
In spite of being a letrec it's not really special. It allows for the expression (the lambda, in this case) to call itself. This way you can do recursion. More on letrec and let here.
Now for the map function you wrote, you are almost there. There is an issue with your two last cases. If the list is not empty you want to take the first element, apply your function to it and then apply the function to the rest of the list. I think you misunderstand what you actually have written down. Ill elaborate.
Recall that a conditional clause is formed like this:
(cond (test1? consequence)
(test2? consequence2)
(else elsebody))
You have any number of tests with an obligatory consequence. Your evaluator will execute test1? and if that evaluated to #t it will execute the consequence as the result of the entire conditional. If test1? and test2? fail it will execute elsebody.
Sidenote
Everything in Scheme is truthy except for #f (false). For example:
(if (lambda (x) x)
1
2)
This if test will evaluate to 1 because the if test will check if (lambda (x) x) is truthy, which it is. It is a lambda. Truthy values are values that will evaluate to true in an expression where truth values are expected (e.g., if and cond).
Now for your cond. The first case of your cond will test if L is null. If that is evaluated to #t, you return the empty list. That is indeed correct. Mapping something over the empty list is just the empty list.
The second case ((f (car L))) literally states "if f is true, then return the car of L".
The else case states "otherwise, return the result mymap on the rest of my list L".
What I think you really want to do is use an if test. If the list is empty, return the empty list. If it is not empty, apply the function to the first element of the list. Map the function over the rest of the list, and then add the result of applying the function the first element of the list to that result.
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
So what you want might look look this:
(define (mymap f L)
(cond ((null? L) '())
(else
(cons (f (car L))
(mymap f (cdr L))))))
Using an if:
(define (mymap f L)
(if (null? L) '()
(cons (f (car L))
(mymap f (cdr L)))))
Since you are new to Scheme this function will do just fine. Try and understand it. However, there are better and faster ways to implement this kind of functions. Read this page to understand things like accumulator functions and tail recursion. I will not go in to detail about everything here since its 1) not the question and 2) might be information overload.
If you're taking on implementing your own list procedures, you should probably make sure they're using a proper tail call, when possible
(define (map f xs)
(define (loop xs ys)
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys))))
(loop (reverse xs) empty))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)
Or you can make this a little sweeter with the named let expression, as seen in your original code. This one, however, uses a proper tail call
(define (map f xs)
(let loop ([xs (reverse xs)] [ys empty])
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys)))))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)

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

Resources