Replacing a symbol in a symbolic expression - functional-programming

I wish to replace the first occurrence of a symbol within pairs. For example:
take
(define n '((a . b) . (a . d)))
and i define a method context to replace the first instance (left most) of X with '()
replacing a should give me:
((() . b) a . d)
however i am stuck as my method replaces ALL instances and i am not sure how to add a check for this.
my code is as follows:
(define (context s sym)
(cond ((null? s) #f)
((atom? s)
(if (equal? s sym) '() s ))
(else (cons (context (car s) sym)
(context (cdr s) sym)))))
which gives : ((() . b) () . d)
any help? Thank you

The quickest way is to use a flag indicating whether the replacement has already been done, something along the lines of:
(define (context sxp sym)
(define done #f)
(let loop ((sxp sxp))
(cond (done sxp)
((pair? sxp) (cons (loop (car sxp)) (loop (cdr sxp))))
((eq? sym sxp) (set! done #t) '())
(else sxp))))
It's not very elegant to use set!, but the alternative would be to have the procedure return 2 values, and the resulting let-values code would be even worse in terms of readability IMO.
Also note that I didn't use atom? because it's not defined in standard Scheme; the usual way is to successively test null? then pair?, and handle the atom case in the else clause.

This is a bit more general (you can replace things other than symbols, and you can customize the test, and you can specify any particular number of instances to replace, not just one), and may be a little bit more complicated at first glance than what you're looking for, but here's a solution that works by internally using a continuation-passing style helper function. The main function, subst-n takes a new element, and old element, a tree, a test, and a count. It replaces the first count occurrences of new (as compared with test) with old (or all, if count is not a non-negative integer).
(define (subst-n new old tree test count)
(let substs ((tree tree)
(count count)
(k (lambda (tree count) tree)))
(cond
;; If count is a number and zero, we've replaced enough
;; and can just "return" this tree unchanged.
((and (number? count) (zero? count))
(k tree count))
;; If the tree is the old element, then "return" the new
;; element, with a decremented count (if count is a number).
((test old tree)
(k new (if (number? count) (- count 1) count)))
;; If tree is a pair, then recurse on the left side,
;; with a continuation that will recurse on the right
;; side, and then put the sides together.
((pair? tree)
(substs (car tree) count
(lambda (left count)
(substs (cdr tree) count
(lambda (right count)
(k (cons left right) count))))))
;; Otherwise, there's nothing to do but return this
;; tree with the unchanged count.
(else
(k tree count)))))
> (display (subst-n '() 'a '((a . b) . (a . d)) eq? 1))
((() . b) a . d)
> (display (subst-n '() 'a '((a . b) . (a . d)) eq? 2))
((() . b) () . d)

Related

I'm trying to understand this piece of Scheme code, can someone explain it to me?

I found this Scheme code on the internet, it outputs all subsets given a list, can someone explain how it works?
(define (subsets s) (if (null? s)
(list ())
(let ((rest (subsets (cdr s))))(append rest (map (lambda (x) (cons (car s) x)) rest)))))
(subsets '(a b c))
You really need to format it:
(define (subsets s)
(if (null? s)
(list ())
(let ((rest (subsets (cdr s))))
(append rest
(map (lambda (x)
(cons (car s) x))
rest)))))
What it does is return (()) for the argument '()
For a one element argument eg. '(b) if binds rest to the subsets of every element execept the first.. Which is no elements so rest is (()) and then it returns a list consisting of all the elements in rest as well as each list element of rest with b added to front. Thus (() (b)).
For a two element argument eg. '(a b) it binds rest to the subsets of every element except the first. Which is (b) so we know from above that it is (() (b)) and we know it will use those as well as every element with a added to the beginning: (() (b) (a) (a b))
I could go on but I'm guessing you get the picture?

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

Code of filter that works with constants not symbols

(define-struct pizza (size toppings))
;; Constants for testing
(define (meat item)
(symbol=? 'meat item))
(define (tomatoes item)
(symbol=? 'tomatoes item))
(define (cheese item)
(symbol=? 'cheese item))
(define (pepperoni item)
(symbol=? 'pepperoni item))
(define (hot-peppers item)
(symbol=? 'hot-peppers item))
(define (count-toppings order topping)
(cond [(empty? order) 0]
[else
(local
[(define (single-pizza-tops pizza top)
(length (filter top (pizza-toppings pizza))))
(define (list-of-nums lop tops)
(list (single-pizza-tops (first lop) tops)
(single-pizza-tops (first (rest lop)) tops)
(single-pizza-tops (first (rest (rest lop))) tops)))]
(foldr + 0 (list-of-nums order topping)))]))
Turns out my code works fine with the defined constants, but count-toppings wont work with a symbol for 'topping?
Does anyone know a way to modify my filter function so that if I input a symbol for toppings, this code will work the same way?
Map and filter can be implemented in terms of foldr and cons. Since you aren't building a list you can disregard filter and map. In general though to map recursion to higher-order function you can look at type signatures. The more difficult way is to manually match your code to that of the functions.
Map takes a list, a function or arity one, and returns a list of the function mapped to each element of the list or (a -> b) -> [a] -> [b] in Haskell notaion.
(define (map f L) ;niave implementation pared down for simplicity
(if (null? L)
'()
(cons (f (car L)) (map f (cdr L)))))
Filter takes a predicate of arity one, and a list, and returns a list that safisfies that predicate. or (a -> bool) -> [a] -> [a] in Haskell.
(define (filter pred L) ;dirro
(cond ((null? L) '())
((pred (car L))
(cons (car L)
(filter pred (cdr L))))
(else (filter pred (cdr L)))))
Foldr takes an a function that that has arity two, an accumulator value, and a list and returns the accumulator. or (a -> b -> b) -> b -> [a] -> b in haskell.
(define (foldr kons knil L) ;ditto
(if (null? L)
knil
(kons (car L) (foldr kons knil (cdr L)))))
So the trick of it at first is assuaging the argument from your function to fit. In both your funcitons you have a cond clause [(empty? topping-list) 0], which suggests knil should be 0.
In count-topping's else statement you call +, which at first glance suggests kons should be a +, however your list isn't numbers directly, meaning youll have to wrap in in a lambda statement, or create a helper function. (lambda (x acc) (+ (single-pizza-toppings (pizza-toppings x) atop) acc))
To put it together
(define (count-topping alop atop)
(foldr (lambda (x acc)
(+ (single-pizza-toppings (pizza-toppings x) atop)
acc))
0
alop))
Now the interesting one, single-pizza-toppings will look very similar. Execpt that the lambda statement will contain an if statment that returns 1 if x is a symbol equal to topping and 0 otherwise. Or you can do something even simpler.
(define (single-pizza-toppings topping-list topping)
(foldr (lambda (x acc)
(+ 1 acc))
0
(filter (lammba (x) (symbol=? x topping))
topping-list)))
That filter filter insures every x going to the foldr is a topping so you can just ignore it and add to the accumulator.
Assuming that we have the first, we can define the second by
Count the occurrences of the topping in each pizza using the first function, by way of map
Compute the sum of the resulting list
That is,
(define (count-toppings pizzas topping)
(sum (map (lambda (p) (single-pizza-toppings (pizza-toppings p) topping)) pizzas)))
For the first function, we can use filter to get a list of all occurrences of the given topping.
The number of occurrences is the length of the result:
(define (single-pizza-toppings toppings topping)
(length (filter (lambda (t) (symbol=? t topping)) toppings)))
Both functions consist of a transformation of the input into the data we're interested in, map and filter, followed by a "reduction", sum and length.
This is a very common pattern.
And if you don't have sum:
(define (sum ts)
(foldr (lambda (x acc) (+ x acc)) 0 ts))
Looks like your first step will be to put together a complete set of test cases. If you're using DrRacket, you might want to enable "Syntactic Test Suite Coverage" in the "Choose Language..." menu to make sure you have a good set of tests. That's the first step....

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