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

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.

Related

What is Classifier and Transformer in MIT Scheme?

In the following scheme code, accumulate does right-fold. When I tried to run using mit scheme. I ran into following error:
Transformer may not be used as an expression: #[classifier-item 13]
Classifier may not be used as an expression: #[classifier-item 12]
I google searched but didn't find useful information. Is it related a macro?
; This function is copied from SICP chapter 2
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
; works as expected
(accumulate
(lambda (x y) (or x y)) ; replace or with and also works
#f
'(#t #f #t #f #f)
))
; does not work
; error: Classifier may not be used as an expression: #[classifier-item 12]
(accumulate
or
#f
'(#t #f #t #f #f)
))
; does not work
; error: Transformer may not be used as an expression: #[classifier-item 13]
(accumulate
and
#f
'(#t #f #t #f #f)
))
Macros can be passed around in some languages, but not in Scheme and Common Lisp. The reason is that macros should be able to be expanded ahead of time. eg.
(define (cmp a b)
(cond ((< a b) -1)
((> a b) 1)
(else 0)))
Now a compiling Scheme will expand each node recursively replacing it with the expansion until it is no change:
(define (cmp a b)
(if (< a b)
(begin -1)
(cond ((> a b) 1)
(else 0))))
(define (cmp a b)
(if (< a b)
-1
(cond ((> a b) 1)
(else 0))))
(define (cmp a b)
(if (< a b)
-1
(if (> a b)
(begin 1)
(cond (else 0)))))
(define (cmp a b)
(if (< a b)
-1
(if (> a b)
1
(cond (else 0)))))
; end result
(define (cmp a b)
(if (< a b)
-1
(if (> a b)
1
0)))
From this point of cond doesn't need to exist in the underlying language at all since you'll never ever use it, but how would this have to be implemented to work:
(define (test syntax a b)
(syntax a b))
(test or #f #t)
For this to work the underlying language needs to know what or is even after expansion since syntax would need to be bound to or and then the transformation can happen. But when the code runs the macro expansion has already happened and in most implementations you would see something indicating that or is an unbound variable. It seems like MIT Scheme has added error checking for top level syntax syntax that will fire an error if you don't override it. Eg. if you add this you will not see any problems whatsoever:
(define (or a b) (if a a b))
(define (and a b) (if a b #f))
Now after those lines any reference to and and or are not the syntax, but these procedures. There are no reserved words in Scheme so if you do something crazy, like defining define you just cannot use it for the rest f that scope:
(define define display) ; defiens define as a top level variable
(define define) ; prints the representation of the function display
(define test 10) ; fail since test is an undefined variable so it cannot be displayed.
I created a interpreted lisp with macros that actually could be passed, but it isn't very useful and the chances of optimization is greatly reduced.
Yes it's related to the macros / special forms like and and or.
You can make it work simply by wrapping them as lambdas, (accumulate (lambda (a b) (or a b)) ...) -- the results will be correct but of course there won't be any short-circuiting then. The op is a function and functions receive their arguments already evaluated.
Either hide the arguments behind lambdas ((lambda () ...)) and evaluate them manually as needed, or define specific versions each for each macro op, like
(define (accumulate-or initial sequence)
(if (null? sequence)
initial
(or (car sequence)
(accumulate-or initial (cdr sequence)))))
Here sequence will still be evaluated in full before the call to accumulate-or, but at least the accumulate-or won't be working through it even after the result is already known.
If sequence contains some results of heavy computations which you want to avoid in case they aren't needed, look into using "lazy sequences" for that.

Maximum recursion error [duplicate]

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

Efficiency issue on Guile SCHEME: member and equal?

I am new on SCHEME programming and after some while I succeeded on writing a couple of scripts to deal with long maths formulas.
The issue is that its execution is pretty slow. After profiling I realized that the execution takes about 35% of the time executing the built-in functions equal? and member.
My question is regarding whether there exist more efficient version of those functions or I should re-factor the code in order to remove its calls?
I'm about to re-write the code so I would really appreciate any piece of advice.
Thanks!
EDIT 1:
I add some code for making the question clearer. The following function takes two parameters, a pair (x,y) and a term, x and y are usually variable names(symbols), but they may be a symbol and a number, a list and a symbol, etc. The term is a list such as
(+ w y z (* (- 1) x))
so after the function execution I would get something like
(+ w z)
The code looks like the following:
(define (simp-by-term_eq t_CC t)
(cond
((and (member (list '* (list '- 1) (car t_CC)) (cdr t))
(member (cadr t_CC) (cdr t)))
(delete-1st (cadr t_CC)
(delete-1st (list '* (list '- 1) (car t_CC)) (cdr t)))
)
((and (member (list '* (car t_CC) (list '- 1)) (cdr t))
(member (cadr t_CC) (cdr t)))
(delete-1st (cadr t_CC)
(delete-1st (list '* (car t_CC) (list '- 1)) (cdr t)))
)
(else t)
)
)
There are several conditions like the previous one on the function.
The equal function calls are mainly used into filter callse such as
(filter (lambda (x) (and (not (equal? (list '* (car t_CC) (list '- 1)) x))
(not (equal? (list '* (list '- 1) (car t_CC)) x)))) t)
equal? needs to test every part of list structure so basically it traverses both operands until it has touched all sequences and compared all atomic values. If you need to test if it's the same you can use eq? which only checks that the pair has the same address. Thus it will evaluate to #f even when the list structure look the same. Sometimes that's ok. eqv? is similar to eq? but it also works for numbers and characters (but not strings).
You can use memq that uses eq? instead of equal? and you can use memqv that uses eqv? which also works for numbers and characters.
I'm not that familiar with Guile but if you have performance issues and are using member perhaps you should consider hash tables instead?
It could happen you need to rethink the algorithm you use too if you really need to use equal?, but without specific code it's difficult to be more specific.

Why doesn't this scheme program work as expected?

(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

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