Scheme two lists intersection - functional-programming

I've written this code
(define (in-list? val ls)
(if (null? ls) #f
(if
(= (car ls) val) #t
(in-list? val (cdr ls))
)
)
)
(define (intersect ls1 ls2)
(if (null? ls1)
'()
(if (in-list? (car ls1) ls2)
(cons (car ls1) (intersect (cdr ls1) ls2))
(intersect (cdr ls1) ls2)
)
)
)
It works correctly if I ask (intersect '(1 2 3) '(1 4 7)) but it returns empty list when I try (intersect '(a b c) '(a b d))

Related

Why does List function call return runtime error in Scheme?

Getting an error for my binary search tree that I created in scheme.
$gosh main.sc
*** ERROR: list required, but got 5
Stack Trace:
_______________________________________
This is my code. I think the error has to do with how I am calling the functions, but I am not sure what exactly is wrong. I am calling the insert function with the two required parameters: tree, and a value of 5.
(define (member? t v)
(cond
((null? t)
#f
)
((< node (car t))
(member? (cadr t) v))
((> node (car t))
(member? (caddr t) v))
(else
#t
)
)
)
(define (insert t v)
(cond
((null? t)
(list v '() '())
)
((< v (car t))
(list (car t) (insert (cadr t) v) (caddr t))
)
((>= v (car t))
(list (car t) (cadr t) (insert (caddr t) v))
)
(else
t
)
)
)
(define (fold func val lst)
(if (null? lst) val (fold func (func val (car lst)) (cdr lst))))
(define (build lst)
(fold (lambda (t v) (insert t v)) '() lst))
(define t (list 10 '() '()))
(insert t 5)
display (member t 5)
display t
You care calling (member t 5) which is the same as (member '(10 '() '()) 5). Now member is not the same as your defined member? since it has a different name. member is the core library that looks like this:
(define (member obj lst)
(cond ((null? lst) #f)
((equal? obj (car lst)) lst)
(else (member obj (cdr lst)))))
Your member? has the two parameters swapped so when you miswrote the name and used the report version member 5 is not null, then it will do (car 5) and that will fail miserably. The error message that 5 is not of the required type list is pretty decent. It might spell the beans that it was member that failed though.
Another thing. If you replace the call to member with a call to member? you hit more problems. You use a variable node that is not defined anywhere.
The indentation and placing of parentheses is not goo lisp style. Your code should be written like this:
;; node doesn't exist in OPs code, but my implementation doesn't like member? without it
(define node 5)
;; possible typo by using the variable node ?
(define (member? t v)
(cond
((null? t)
#f)
((< node (car t))
(member? (cadr t) v))
((> node (car t))
(member? (caddr t) v))
(else
#t)))
(define (insert t v)
(cond
((null? t)
(list v '() '()))
((< v (car t))
(list (car t) (insert (cadr t) v) (caddr t)))
((>= v (car t))
(list (car t) (cadr t) (insert (caddr t) v)))
(else
t)))
(define (fold func val lst)
(if (null? lst) val (fold func (func val (car lst)) (cdr lst))))
(define (build lst)
(fold (lambda (t v) (insert t v)) '() lst))
(define t (list 10 '() '()))
(insert t 5)
;; NB doesn't call a procedure, just evaluates it.
display
;; Here the arguments are the wrong order and you don't use memeber?
(member t 5)
;; NB doesn't call a procedure, just evaluates it.
display
t

Leave only the elements that are not repeated in a given list IN SCHEME [duplicate]

I'm trying to teach myself functional language thinking and have written a procedure that takes a list and returns a list with duplicates filtered out. This works, but the output list is sorted in the order in which the last instance of each duplicate item is found in the input list.
(define (inlist L n)
(cond
((null? L) #f)
((= (car L) n) #t)
(else (inlist (cdr L) n))
))
(define (uniquelist L)
(cond
((null? L) '())
((= 1 (length L)) L)
((inlist (cdr L) (car L)) (uniquelist (cdr L)))
(else (cons (car L) (uniquelist (cdr L))))
))
So..
(uniquelist '(1 1 2 3)) => (1 2 3)
...but...
(uniquelist '(1 2 3 1)) => (2 3 1)
Is there a simple alternative that maintains the order of the first instance of each duplicate?
The best way to solve this problem would be to use Racket's built-in remove-duplicates procedure. But of course, you want to implement the solution from scratch. Here's a way using idiomatic Racket, and notice that we can use member (another built-in function) in place of inlist:
(define (uniquelist L)
(let loop ([lst (reverse L)] [acc empty])
(cond [(empty? lst)
acc]
[(member (first lst) (rest lst))
(loop (rest lst) acc)]
[else
(loop (rest lst) (cons (first lst) acc))])))
Or we can write the same procedure using standard Scheme, as shown in SICP:
(define (uniquelist L)
(let loop ((lst (reverse L)) (acc '()))
(cond ((null? lst)
acc)
((member (car lst) (cdr lst))
(loop (cdr lst) acc))
(else
(loop (cdr lst) (cons (car lst) acc))))))
The above makes use of a named let for iteration, and shows how to write a tail-recursive implementation. It works as expected:
(uniquelist '(1 1 2 3))
=> '(1 2 3)
(uniquelist '(1 2 3 1))
=> '(1 2 3)

"Multiplication of Arbitrary Precision Numbers" in Scheme

The following is code to a problem that I have been working on for a few days. The problem I encountered is that for some reason when I call:
(apa-multi '(7 3 1 2) '(6 1 4))
the return is:
'(4 8 9 5 6 8)
The answer that it should output is
'(4 4 8 9 5 6 8)
When I call:
(apa-multi '(3 1 2) '(6 1 4))
The output is:
'(1 9 1 5 6 8)
which is correct.
I have debugged my code multiple times, and I can't seem to find out what the problem is (by the way, I know that the "remove-empty" function that I wrote is most likely unnecessary). Can anyone tell me where I am going wrong here? (My goal for this problem is to keep the arbitrary precision numbers in list format, and I can not create a function that converts numbers from list->num or num->list.) I believe that I have provided all of the necessary code for someone to work out what I was going for, but if not please let me know. The hint that I have for this is that " Multiplication of d = dndn−1 ...d1 by e = emem−1 ...e1 can be carried out by the rule de=d∗e1 +10∗(d∗em em−1...e2).)"
(define (remove-empty L)
(define (remove-empty-h L accum)
(cond ((null? L) accum)
((null? (car L))
(remove-empty (cdr L)))
(else (cons (car L) (remove-empty-h (cdr L) accum)))))
(remove-empty-h L '()))
(define (apa-add lst1 lst2)
(define (apa-add-h lst1 lst2 carry)
(cond ((and (null? lst1) (null? lst2))
(if (not (= 0 carry))
(list carry)
'()))
((null? lst1) (append (apa-add-h lst1 '() carry)
(list (+ (car (reverse-l lst2)) carry))
(reverse-l(cdr (reverse-l lst2)))))
((null? lst2) (append (apa-add-h '() lst2 carry)
(list (+ (car (reverse-l lst1)) carry)))
(reverse-l(cdr (reverse-l lst1))))
(else
(append (apa-add-h (cdr lst1) (cdr lst2) (quotient (+ (car lst1) (car lst2) carry) 10))
(list (modulo (+ (car lst1) (car lst2) carry) 10))))))
(apa-add-h (reverse-l lst1) (reverse-l lst2) 0))
(define (d-multiply lst factor)
(define (d-multiply-h lst factor carry)
(cond ((null? lst) (if (= carry 0)
'()
(list carry)))
((>= (+ (* (car lst) factor) carry) 10)
(append ;(list (check-null-and-carry-mult lst carry))
(d-multiply-h (cdr lst) factor (quotient (+ (* (car lst) factor) carry) 10))
(list (modulo (+ (* (car lst) factor) carry) 10))))
(else (append ;(list (check-null-and-carry-mult lst carry))
(d-multiply-h (cdr lst) factor (quotient(+ (* (car lst) factor) carry) 10))
(list (+ (* (car lst) factor) carry))))))
(remove-empty (d-multiply-h (reverse-l lst) factor 0)))
(define (nlength l)
(if (null? l)
0
(+ 1 (nlength (cdr l)))))
(define (apa-multi d e)
(define temp '())
(cond ((= (max (nlength e) (nlength d)) (nlength e))
(set! temp e)
(set! e d)
(set! d temp))
(else
(set! temp d)
(set! d e)
(set! e temp)))
(define (apa-multi-h d e)
(cond ((null? e) (list 0))
(else (append (apa-add (d-multiply d (car e))
(append (apa-multi-h d (cdr e)) (list 0)))))))
(apa-multi-h d (reverse-l e)))
The reason your code does not work is because your apa-add is broken. For example:
> (apa-add '(7 3 1 2) '(6 1 4))
'(9 2 6)
> (+ 7312 614)
7926
The rest of your code seems to work, at least for your 2 examples, if you use a working apa-add.
I admit I did not try to understand your code fully; the poor formatting and the set! procedures at the end made me want to start from scratch. So even if you could simple correct your apa-add, maybe have a look at my version anyway, because it is way shorter and probably easier to understand.
Building on my previous answer for apa-add multiplication is a matter of apa-adding, multiplying one list by a digit at a time, and adding zeroes at the end of the intermediary multiplications just as you'd do it manually:
(define (car0 lst) (if (empty? lst) 0 (car lst)))
(define (cdr0 lst) (if (empty? lst) empty (cdr lst)))
(define (apa-add l1 l2) ; apa-add (see https://stackoverflow.com/a/19597007/1193075)
(let loop ((l1 (reverse l1)) (l2 (reverse l2)) (carry 0) (res '()))
(if (and (null? l1) (null? l2) (= 0 carry))
res
(let* ((d1 (car0 l1)) (d2 (car0 l2)) (ad (+ d1 d2 carry)) (dn (modulo ad 10)))
(loop (cdr0 l1) (cdr0 l2) (quotient (- ad dn) 10) (cons dn res))))))
(define (mult1 n lst) ; multiply a list by one digit
(let loop ((lst (reverse lst)) (carry 0) (res '()))
(if (and (null? lst) (= 0 carry))
res
(let* ((c (car0 lst)) (m (+ (* n c) carry)) (m0 (modulo m 10)))
(loop (cdr0 lst) (quotient (- m m0) 10) (cons m0 res))))))
(define (apa-multi l1 l2) ; full multiplication
(let loop ((l2 (reverse l2)) (app '()) (res '()))
(if (null? l2)
res
(let* ((d2 (car l2)) (m (mult1 d2 l1)) (r (append m app)))
(loop (cdr l2) (cons '0 app) (apa-add r res))))))
Not sure why it doesn't work, all those appends and reverses are hard to follow, and not sure what's going on with all that set! stuff. Putting the state into a tail call is a lot easier to follow and usually more efficient to boot.
(define (apa-add . Lists)
(define (cdrs-no-null L)
(cond ((null? L) '())
((null? (cdar l)) (cdrs-no-null (cdr L)))
(else (cons (cdar l) (cdrs-no-null (cdr l))))))
(let loop ((carry 0) (Lists (map reverse Lists)) (sum '()))
(if (null? Lists)
(if (zero? carry) sum (cons carry sum))
(loop (quotient (fold + carry (map car Lists)) 10)
(cdrs-no-null Lists)
(cons (modulo (fold + carry (map car Lists)) 10) sum)))))
(define (apa-mult . Lists)
(define (mult-by-factor n order L)
(let loop ((order order) (L (reverse L)) (carry 0) (sum '()))
(cond ((> order 0) (loop (- order 1) L carry (cons 0 sum)))
((null? L) (if (zero? carry)
sum
(cons carry sum))) ;;bug here if carry > 9
(else (loop 0
(cdr L)
(quotient (+ carry (* n (car L))) 10)
(cons (modulo (+ carry (* n (car L))) 10) sum))))))
(define (apa-mult2 L1 L2)
(let ((rL1 (reverse L1))
(rL2 (reverse L2))
(zip-with-order
(lambda (L)
(let loop ((order 0) (L L) (accum '()))
(if (null? L)
accum
(loop (+ 1 order)
(cdr L)
(cons (cons (car L) order) accum)))))))
(fold apa-add '(0) (map (lambda (x)
(mult-by-factor (car x) (cdr x) L2))
(zip-with-order rl1)))))
(fold apa-mult2 '(1) Lists)))
(apa-mult '(3 1 2) '(6 1 4)))
;Value 7: (1 9 1 5 6 8)
(apa-mult '(2 0 0) '(3 1 2) '(6 1 4))
;Value 8: (3 8 3 1 3 6 0 0)
(apa-mult '(7 3 1 2) '(6 1 4))
;Value 9: (4 4 8 9 5 6 8)

"Addition of arbitrary precision numbers" in Scheme

I am trying to add two numbers (from lists) together in scheme while preserving list format. However, when the numbers being used for calculations add to something greater than or equal to 10 I get an undesired result. For example:
(define (reverse lst)
(if (null? lst)
'()
(append (reverse (cdr lst))
(list (car lst)))))
(define (apa-add lst1 lst2)
(cond ((null? lst1) lst2)
((null? lst2) lst1)
((>= (+ (car lst1) (car lst2)) 10)
(append (apa-add (cdr lst1) (cdr lst2))
(list (quotient(+ (car lst1) (car lst2)) 10))
(list (modulo (+ (car lst1) (car lst2)) 10))))
(else
(append (apa-add (cdr lst1) (cdr lst2))
(list (+ (car lst1) (car lst2)))))))
(apa-add (reverse '(4 4 5)) (reverse'(3 5 8)))
returns
'(7 9 1 3)
How can I modify my code to fix this error? I wanted to use a let statement so I could add the evaluation of (quotient (+ (car lst1) (car lst2)) 10) to (list (+ (car lst1) (car lst2))) of the next call, but I couldn't think of how to do this.
Making this into a tail call simplifies things a bit.
(define (apa-add lst1 lst2)
(let loop ((carry 0) (L1 (reverse lst1)) (L2 (reverse lst2)) (sum '()))
(cond ((and (null? l1) (null? l2))
(if (zero? carry) sum (cons carry sum)))
((null? L1)
(loop (quotient (+ carry (car l2)) 10)
'()
(cdr L2)
(cons (modulo (+ carry (car l2)) 10) sum)))
((null? L2)
(loop (quotient (+ carry (car l1)) 10)
(cdr l1)
'()
(cons (modulo (+ carry (car l1)) 10) sum)))
(else
(loop (quotient (+ carry (car l1) (car l2)) 10)
(cdr l1)
(cdr l2)
(cons (modulo (+ carry (car l1) (car l2)) 10) sum))))))
(apa-add (list 4 4 5) (list 3 5 8))
;Value 4: (8 0 3)
probably wouldnt be too hard to convert to an n-arity function.
(define (apa-add . Lists)
(define (cdrs-no-null L)
(cond ((null? L) '())
((null? (cdar l)) (cdrs-no-null (cdr L)))
(else (cons (cdar l) (cdrs-no-null (cdr l))))))
(let loop ((carry 0) (Lists (map reverse Lists)) (sum '()))
(if (null? Lists)
(if (zero? carry) sum (cons carry sum))
(loop (quotient (fold + carry (map car Lists)) 10)
(cdrs-no-null Lists)
(cons (modulo (fold + carry (map car Lists)) 10) sum)))))
(apa-add (list 4 4 5) (list 3 5 8) (list 1 0 2 7))
;Value 11: (1 8 3 0)
(apa-add (list 4 4 5) (list 3 5 8))
;Value 12: (8 0 3)

Scheme List of lists zipping

If my input is a list of lists, then I want to output a list with elements from the input so that they are shuffled like a deck of playing cards.
For example, if input is '((1 2 3) (4 5)) then I want output to show up as '(1 4 2 5 3).
My idea is to first remove an element from the first list inside of a list, and then move that list of a list to the back of the list. This way, the first element of the next list of a list can then be appended.
Here is my code so far:
(define (shuffle ls)
(if (null? ls) '()
(cond ((null? car (ls)) (append (cdr (ls)) (list (cdr(car(ls)))))))
(else (car (car (ls)))
(append (cdr (ls)) (list (cdr (car (ls))))
(shuffle (cdr (ls)))))))
[All the code snippets here require SRFI 1 to be loaded first.]
What you seem to be wanting is to zip the lists:
> (zip '(1 2 3) '(4 5))
((1 4) (2 5))
However, as you can see, this stops when it gets to the end of the shortest list. Maybe you can write a custom zip that will stop after all elements are exhausted:
(define (my-zip l1 l2)
(cond ((and (null? l1) (null? l2)) '())
((null? l1) (cons (car l2) (my-zip l1 (cdr l2))))
((null? l2) (cons (car l1) (my-zip (cdr l1) l2)))
(else (cons* (car l1) (car l2) (my-zip (cdr l1) (cdr l2))))))
Let's try it out!
> (my-zip '(1 2 3) '(4 5))
(1 4 2 5 3)
> (my-zip '(1 2 3) '(4 5 6 7))
(1 4 2 5 3 6 7)
this would work too... i use chicken scheme so i have to "import" filter from srfi-1.
(use srfi-1)
(define *deck* '((1 2 3 4) (5 6 7) (9 10 11 12)))
(define nullcar?
(lambda (x)
(if (not (null? x))
(null? (car x)))))
(define nullcdr?
(lambda (x)
(if (not (null? x))
(null? (cdr x)))))
(define notnulls
(lambda (x)
(filter (lambda (e)
(not (null? e)))
x)))
(define firsts
(lambda (l)
(if (not (null? l))
(map (lambda (x)
(if (not (null? x))
(car x)
'()))
l))))
(define shuf
(lambda (d)
(notnulls
(append (firsts d)
(if (not (nullcar? d))
(if (not (nullcdr? d))
(shuf (map cdr (notnulls d)))
'())
'())))))
cheers!

Resources