Why doesn't this scheme program work as expected? - scheme

(define wadd (lambda (i L)
(if (null? L) 0
(+ i (car L)))
(set! i (+ i (car L)))
(set! L (cdr L))))
(wadd 9 '(1 2 3))
This returns nothing. I expect it to do (3 + (2 + (9 + 1)), which should equate to 15. Am I using set! the wrong way? Can I not call set! within an if condition?

I infer from your code that you intended to somehow traverse the list, but there's nothing in the wadd procedure that iterates over the list - no recursive call, no looping instruction, nothing: just a misused conditional and a couple of set!s that only get executed once. I won't try to fix the procedure in the question, is beyond repair - I'd rather show you the correct way to solve the problem. You want something along these lines:
(define wadd
(lambda (i L)
(let loop ((L L)
(acc i))
(if (null? L)
acc
(loop (cdr L) (+ (car L) acc))))))
When executed, the previous procedure will evaluate this expression: (wadd 9 '(1 2 3)) like this:
(+ 3 (+ 2 (+ 1 9))). Notice that, as pointed by #Maxwell, the above operation can be expressed more concisely using foldl:
(define wadd
(lambda (i L)
(foldl + i L)))
As a general rule, in Scheme you won't use assignments (the set! instruction) as frequently as you would in an imperative, C-like language - a functional-programming style is preferred, which relies heavily on recursion and operations that don't mutate state.

I think that if you fix your indentation, your problems will become more obvious.
The function set! returns <#void> (or something of similar nothingness). Your lambda wadd does the following things:
Check if L is null, and either evaluate to 0 or i + (car L), and then throw away the result.
Modify i and evaluate to nothing
Modify L and return nothing
If you put multiple statements in a lambda, they are wrapped in a begin statement explicitly:
(lambda () 1 2 3) => (lambda () (begin 1 2 3))
In a begin statement of multiple expressions in a sequence, the entire begin evaluates to the last statement's result:
(begin 1 2 3) => 3

Related

How to count the number of if-statements in a separate file of code

I am trying to write a scheme program that counts the number of if-statement a file containing code. I know how to read in the file but I don't know how to go about counting the number of if-statements.
This is very hard without actually implementing reducing the language to a more primitive form. As an example, imagine this:
(count-ifs '(let ((if +))
(if 1 2 3)))
; ==> 0
0 is the correct amount as if is a binding shadowing if and Scheme supports shadowing so the result of that expression is 6 and not 2. let can be rewritten such that you can check this instead:
(count-ifs '((lambda (if)
(if 1 2 3))
+))
; ==> 0
It might not look like an improvement, but here you can actually fix it:
(define (count-ifs expr)
(let helper ((expr expr) (count 0))
(if (or (not (list? expr))
(and (eq? (car expr) 'lambda)
(memq 'if (cadr expr))))
count
(foldl helper
(if (eq? (car expr) 'if)
(add1 count)
count)
expr))))
(count-ifs '((lambda (if)
(if 1 2 3))
(if #t + (if if if))))
; ==> 2
Challenge is to expand the macros. You actually need to make a macro expander to rewrite the code such that the only form making bindings would be lambda. This is the same amount of work as making 80% of a Scheme compiler since once you've dumbed it down the rest is easy.
A simple way to do it could be recursion structure like this:
(define (count-ifs exp)
(+ (if-expression? exp 1 0)))
(if (pair? exp)
(+ (count-ifs (car exp)) (count-ifs (cdr exp))))
0)))
But this might overcount.
A more correct way to do it would be to process the code by checking each type of expression you see - and when you enter a lambda you need to add the variables it binds to a shadowed symbols list.

multiplying list of items by a certain number 'x'

How would you write a procedure that multiplies each element of the list with a given number (x).If I give a list '(1 2 3) and x=3, the procedure should return (3 6 9)
My try:
(define (mul-list list x)
(if (null? list)
1
(list(* x (car list))(mul-list (cdr list)))))
The above code doesnt seem to work.What changes do I have to make ? Please help
Thanks in advance.
This is the text book example where you should use map, instead of reinventing the wheel:
(define (mul-list lst x)
(map (lambda (n) (* x n)) lst))
But I guess that you want to implement it from scratch. Your code has the following problems:
You should not call list a parameter, that clashes with the built-in procedure of the same name - one that you're currently trying to use!
The base case should return an empty list, given that we're building a list as output
We build lists by consing elements, not by calling list
You forgot to pass the second parameter to the recursive call of mul-list
This should fix all the bugs:
(define (mul-list lst x)
(if (null? lst)
'()
(cons (* x (car lst))
(mul-list (cdr lst) x))))
Either way, it works as expected:
(mul-list '(1 2 3) 3)
=> '(3 6 9)
For and its extensions (for*, for/list, for/first, for/last, for/sum, for/product, for/and, for/or etc: https://docs.racket-lang.org/reference/for.html) are very useful for loops in Racket:
(define (ml2 lst x)
(for/list ((item lst))
(* item x)))
Testing:
(ml2 '(1 2 3) 3)
Output:
'(3 6 9)
I find that in many cases, 'for' implementation provides short, simple and easily understandable code.

Scheme: The object () is not applicable

It's a beginner question. However it's more than 2 hours that I'm trying to find out the error (I've also made searches) but without success.
(define a (lambda (l i) (
(cond ((null? l) l)
(else (cons (cons (car l) i) (a (cdr l) i))))
)))
The function a should pair the atom i with each item of l. For example:
(a '(1 2 3) 4) should return ((1 4) (2 4) (3 4))
However when I try to use invoke the function I get:
The object () is not applicable
What's the error in my function?
I am using mit-scheme --load a.lisp to load the file. Then I invoke the function a by typing in interactive mode.
The error, as usually happens in lisp languages, depends on the wrong use of the parentheses, in this case the extra parentheses that enclose the body of the function.
Remove it and the function should work:
(define a (lambda (l i)
(cond ((null? l) l)
(else (cons (cons (car l) i) (a (cdr l) i))))))
Rember that in lisp parentheses are not a way of enclosing expressions, but are an important part of the syntax: ((+ 2 3)) is completely different from (+ 2 3). The latter expression means: sum the value of the numbers 2 and 3 and return the result. The former means: sum the value of the numbers 2 and 3, get the result (the number 5), and call it as a function with zero parameters. This obviously will cause an error since 5 is not a function...

Scheme: cannot use #t in an if statement

Apologies if the question title is a bit confusing. Maybe after you are through reading it, you can suggest me a better title.
As a part of a homework assignment for an online course, I wrote an iterative procedure in mit-scheme to display number from 1 to a given number.
The code below works fine:
(define (count2-iter num)
(define (iter counter)
(cond ((> counter num) #t)
(else (display counter)
(iter (+ counter 1)))))
(iter 1))
The output:
1 ]=> (load "count2-iter.scm")
;Loading "count2-iter.scm"... done
;Value: count2-iter
1 ]=> (count2-iter 10)
12345678910
;Value: #t
Personally I do not like using cond for 2 branches only and I tried to use if for this.
(define (count2-iter1 num)
(define (loop idx)
(if (> idx num)
#t
((display idx)
(loop (+ idx 1)))))
(loop 1))
The output:
1 ]=> (count2-iter1 5)
5
;The object #!unspecific is not applicable.
;To continue, call RESTART with an option number:
; (RESTART 2) => Specify a procedure to use in its place.
; (RESTART 1) => Return to read-eval-print level 1.
Why is this? Shouldn't #t be evaluated the same way it was used in cond? Would really appreciate an explanation as I am still new to Scheme.
Try this instead:
(define (count2-iter1 num)
(define (loop idx)
(if (> idx num)
#t
(begin ; notice the difference!
(display idx)
(loop (+ idx 1)))))
(loop 1))
Here's why: when you use an if, there can be only one expression in the consequent part and one in the alternative part. If more than one expression is needed, we have to surround them with a (begin ...). You surrounded the expressions between (...), which is not ok, because parenthesis are used for function application (that's why the error message states that The object #!unspecific is not applicable).
On the other hand, a cond has an implicit begin for each of its clauses when a condition is met. Personally, I prefer to stick with using cond when I need more than one expression after a condition - it's less verbose.

How Do For Loops Work In Scheme?

I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why
(define (bubblesort alist)
;; this is straightforward
(define (swap-pass alist)
(if (eq? (length alist) 1)
alist
(let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
(if (> fst scnd)
(cons scnd (swap-pass (cons fst rest)))
(cons fst (swap-pass (cons scnd rest)))))))
; this is mysterious--what does the 'for' in the next line do?
(let for ((times (length alist))
(val alist))
(if (> times 1)
(for (- times 1) (swap-pass val))
(swap-pass val))))
I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.
Any thoughts on what's going on here?
That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.
(let loop ((times 10))
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))
gets expanded to something like
(letrec ((loop (lambda (times)
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))))
(loop 10))
This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).
What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.
Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.

Resources