Skip to content

Instantly share code, notes, and snippets.

@vdeemann
Last active March 29, 2024 01:29
Show Gist options
  • Save vdeemann/8071ab92d7d89b3c556611a6af37f587 to your computer and use it in GitHub Desktop.
Save vdeemann/8071ab92d7d89b3c556611a6af37f587 to your computer and use it in GitHub Desktop.
the-little-schemer
#lang racket
(require racket/trace)
(define o+
(lambda (n m)
(cond
((zero? m) n)
(else (add1 (o+ n (sub1 m)))))))
;(trace o+)
;(o+ 46 12) ; 58
(define o-
(lambda (n m)
(cond
((zero? m) n)
(else (sub1 (o- n (sub1 m)))))))
; Example of o-
;
;(trace o-)
;(o- 14 3) ; 11
;(o- 17 9) ; 8
(define addtup
(lambda (tup)
(cond
((null? tup) 0)
(else (o+ (car tup) (addtup (cdr tup)))))))
; Examples of addtup
;
;(addtup '(3 5 2 8)) ; 18
;(addtup '(15 6 7 12 3)) ; 43
(define o*
(lambda (n m)
(cond
((zero? m) 0)
(else (o+ n (o* n (sub1 m)))))))
;(o* 5 3) ; 15
;(o* 13 4) ; 52
(define o>
(lambda (n m)
(cond
((zero? n) #f)
((zero? m) #t)
(else
(o> (sub1 n) (sub1 m))))))
; Examples of o>
;
;(o> 12 133) ; #f (false)
;(o> 120 11) ; #t (true)
;(o> 6 6) ; #f
; The o< function compares n with m and returns true if n<m
;
(define o<
(lambda (n m)
(cond
((zero? m) #f)
((zero? n) #t)
(else
(o< (sub1 n) (sub1 m))))))
; Examples of o<
;
;(o< 4 6) ; #t
;(o< 8 3) ; #f
;(o< 6 6) ; #f
(define o=
(lambda (n m)
(cond
((o> n m) #f)
((o< n m) #f)
(else #t))))
; Examples of o=
;
;(o= 5 5) ; #t
;(o= 1 2) ; #f
(define o/
(lambda (n m)
(cond
((o< n m) 0)
(else (add1 (o/ (o- n m) m))))))
; Example of o/
;
;(o/ 15 4) ; 3
(define atom? ;
(lambda (x) ;
(and (not (pair? x)) (not (null? x)))))
#|
; my number? function (does not work with strings)
; what is the definition of a number?
; numbers are considered integers in this case and they are counting numbers
; so this function should sub1 to reach 0 as a terminating case
(define number?
(lambda (n)
(cond
((zero? (sub1 n)) #t)
((zero? n) #t)
(else (number? (sub1 n)))
)))
(trace number?)
(number? 2)
(number? 0)
(number? 'tomato)
|#
; The no-nums function returns a new lat with all numbers removed
;
(define no-nums
(lambda (lat)
(cond
((null? lat) '())
((number? (car lat)) (no-nums (cdr lat)))
(else
(cons (car lat) (no-nums (cdr lat)))))))
; Example of no-nums
;
;(no-nums '(5 pears 6 prunes 9 dates)) ; '(pears prunes dates)
; The eqan? function determines whether two arguments are te same
; It uses eq? for atoms and = for numbers
;
(define eqan?
(lambda (a1 a2)
(cond
((or (number? a1) (number? a2)) #f)
((and (number? a1) (number? a2)) (= a1 a2))
(else
(eq? a1 a2)))))
; Examples of eqan?
;
;(eqan? 3 3) ; #t
;(eqan? 3 4) ; #f
;(eqan? 'a 'a) ; #t
;(eqan? 'a 'b) ; #f
#lang racket
(require racket/trace)
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))
(define rember*
(lambda (a l)
(cond
((null? l) '())
((atom? (car l))
(cond
((eq? (car l) a)
(rember* a (cdr l)))
(else
(cons (car l) (rember* a (cdr l))))))
(else
(cons (rember* a (car l)) (rember* a (cdr l)))))))
(trace rember*)
(trace atom?)
(rember*
'cup
'((coffee) cup ((tea) cup) (and (hick)) cup))
;==> '((coffee) ((tea)) (and (hick)))
(rember*
'sauce
'(((tomato sauce)) ((bean) sauce) (and ((flying)) sauce)))
;==> '(((tomato)) ((bean)) (and ((flying))))
#|
# python while-loop using ChatGPT to be converted tail-recursively
def rember_star(a, lst):
def helper(a, lst):
acc = []
while lst:
if isinstance(lst[0], list):
acc.append(helper(a, lst[0]))
elif lst[0] == a:
pass
else:
acc.append(lst[0])
lst = lst[1:]
return acc
return helper(a, lst)
# Test input where the element to remove is present in the list
print(rember_star(2, [1, [2, 3], 4, [5, 6]])) # Output: [1, [3], 4, [5, 6]]
# Test input where the element to remove is not present in the list
print(rember_star(7, [1, [2, 3], 4, [5, 6]])) # Output: [1, [2, 3], 4, [5, 6]]
# Test input where the list is empty
print(rember_star(2, [])) # Output: []
# Test input where the list contains only the element to remove
print(rember_star(2, [2, 2, 2])) # Output: []
# Test input where the list contains nested sublists
print(rember_star(2, [1, [2, [2, 3]], 4, [5, 6]])) # Output: [1, [[3]], 4, [5, 6]]
To make the `rember*` function tail-recursive, you can use an accumulator parameter to accumulate the result while traversing the list. Here's the modified version:
```scheme
(define rember*
(lambda (a l)
(letrec ((helper (lambda (a l acc)
(cond
((null? l) (reverse acc))
((atom? (car l))
(if (eq? (car l) a)
(helper a (cdr l) acc)
(helper a (cdr l) (cons (car l) acc))))
(else
(helper a (cdr l) (cons (helper a (car l) '()) acc)))))))
(helper a l '()))))
```
In this modified version:
- We introduce a helper function `helper` that takes an additional parameter `acc` as an accumulator.
- The `helper` function accumulates the result in `acc` as it traverses the list `l`.
- When a non-atomic element is encountered, the `helper` function recursively calls itself with `(car l)` and accumulates the result in the `acc`.
- After traversing the entire list, we return the accumulated result, which is reversed to maintain the original order of elements.
This version of `rember*` is tail-recursive because the recursive call `(helper a (cdr l) ...)` is the last operation performed in each branch of the recursion.
|#
; tail-recursive solution from ChatGPT
(define tail-rember*
(lambda (a l)
(letrec ((helper (lambda (a l acc)
(cond
((null? l) (reverse acc))
((atom? (car l))
(if (eq? (car l) a)
(helper a (cdr l) acc)
(helper a (cdr l) (cons (car l) acc))))
(else
(helper a (cdr l) (cons (helper a (car l) '()) acc)))))))
(helper a l '()))))
(trace tail-rember*)
(tail-rember*
'cup
'((coffee) cup ((tea) cup) (and (hick)) cup))
;==> '((coffee) ((tea)) (and (hick)))
(tail-rember*
'sauce
'(((tomato sauce)) ((bean) sauce) (and ((flying)) sauce)))
;==> '(((tomato)) ((bean)) (and ((flying))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment