Trouble with simple calculator program in Scheme - scheme

I need to define a calculator for simple arithmetic expressions in Scheme. For example, when typing (calculator '( 1 + 2)), scheme interpreter will print 3. The calculator will accept expression of any length, and the expression associates to the right. Eg, in (calculator '(1 + 1 - 2 + 3 )) the expression is interpreted as (1 + (1 - (2 + 3))), hence the value is -3. I'm assuming the expression has + and - operators only and there are no brackets in the input. I wrote this program so far:
#lang lazy
(define (calculator exp)
(cond
((null? exp) 0)
(= (length (exp)) 1 exp)
(eq? '+ (cdr (cdr exp)) (+ (car exp) (calculator (cdr (cdr exp)))))
(else (eq? '- (cdr (cdr exp)) (- (car exp) (calculator (cdr (cdr exp)))))))
But when I try something like (calculator '(1 + 1 + 1)), I get this error:
#%module-begin: allowed only around a module body in: (#%module-begin (define
(calculator exp) (cond ((null? exp) 0) (= (length (exp)) 1 exp) (eq? (quote +)
(cdr (cdr exp)) (+ (car exp) (calculator (cdr (cdr exp))))) (else (eq? (quote -)
(cdr (cdr exp)) (- (car exp) (calculator (cdr (cdr exp)))))))) (calculator
(quote (1 + 1 + 1))))
I'm very new to Scheme so any help would be greatly appreciated

The syntax in your code isn't correct. As noted in the comment to your question, you've misplaced some parens. In Scheme you get a large benefit in 'tracking parens' by indenting consistently. Here is a version that gets you mostly there.
(define (calculator exp)
(cond ((null? exp) 0) ; zero terms
((null? (cdr exp)) (car exp)) ; one term only (assumed number)
(else ; assumed three or more terms
(let ((operand1 (car exp))
(operator (cadr exp))
(operands (cddr exp)))
((case operator ; convert operator, a symbol, to its function
((+) +)
((-) -))
operand1
(calculator operands)))))) ; calculate the rest
> (calculator '(1 + 2))
3
> (calculator '(1 - 2 + 3))
-4

In order to convert
1 - 2 + 3
to
(- 1 (+ 2 3))
you need to
cache value 1
apply - to the cached value 1 and the rest of the expression
cache value 2
apply + to the cached value 2 and the rest of the expression
cache value 3
return cached value 3 since your list is empty now
So your have 3 cases:
1) end of list => return cached value
otherwise toggle between
2) cache a value
3) apply the function to the cached value and the rest of the expression
Sample code:
(define (calculator exp)
(define funcs (hasheq '+ + '- -))
(let loop ((exp exp) (toggle #t) (val #f))
(if (empty? exp)
val ; 1) end of list => return cached value
(if toggle
(loop (cdr exp) #f (car exp)) ; 2) cache value
((hash-ref funcs (car exp)) val (loop (cdr exp) #t #f)))))) ; 3) apply the function to the cached value and the rest of the expression

Related

scheme- writing a foldl /fold-left like function that works on first 3 items of the given list

I would like to write a function that gets and infix expression and changes it to prefix.
at first let's assume we only deal with + operator, so I want to change the expression 1+1+1 into: (+ (+ 1 1) 1)
I want to do it using foldl or foldl-like matter:
taking the second item in the list (which is always the operand) appending it with the first and the third (in that order) then I would like the expression we've just appended to become the first item in the list so I would do the same on the rest of the list recursively.
Iv'e tried the following:
(lambda (lst)
(fold-left (lambda (pmLst)
`(,((cadr pmLst) ,(car pmLst) (caddr pmLst)) ,(cddr pmLst)))
'()
lst))
but then I realized that the lambda given to the fold-left has to have 2 arguments but I would like to deal with the first 3 items of the list.
I hope I've made myself clear cause it got a bit tricky..
A fold wont do what you want. If you imagine the expression (5 + 3 + 2) then using a fold with proc as the procedure do this:
(proc 2 (proc '+ (proc 3 (proc '+ (proc 5 '())))))
A way would be to make a function that returns the odd and even elements in their own list so that '(+ 2 - 3) becomes (+ -) and (2 3) and then you could do it like this:
(define (infix->prefix expr)
(if (pair? expr)
(let-values ([(ops args) (split (cdr expr))])
(fold (lambda (op arg acc)
(list op acc (infix->prefix arg)))
(car expr)
ops
args))
expr))
However the size of both is much greater than just rolling your own recursion:
(define (infix->prefix expr)
(define (aux lst acc)
(if (pair? lst)
(aux (cddr lst)
(list (car lst)
acc
(infix->prefix (cadr lst))))
acc))
(if (pair? expr)
(aux (cdr expr) (infix->prefix (car expr)))
expr))
(infix->prefix '(1 + 2 - 3))
; ==> (- (+ 1 2) 3)
There is no operator precedence here. Everything is strictly left to right.

Arithmetic expression parse

I want to parse an arithmetic expression into a binary tree represented as (list left right value). This is my code:
(define (parse exp)
(let loop ([e exp])
(cond
((and (list? e) (or (not (null? (car e))) (not (null? (caddr e)))))
(list (loop (car e)) (loop (caddr e)) (cadr e))))))
(parse '(1 + (2 * 3)))
The result is this and I don't know where from the void appears.
'(#<void> (#<void> #<void> *) +)
You're missing the base case of the recusion (here it's the else in cond form):
(define (parse exp)
(let loop ([e exp])
(cond
((and (list? e) (or (not (null? (car e))) (not (null? (caddr e)))))
(list (loop (car e)) (loop (caddr e)) (cadr e)))
(else e))))
Testing:
> (parse '(1 + (2 * 3)))
'(1 (2 3 *) +)
#<void> is the result of "falling through" the cond form (i.e. no condition matched, and there's no else):
> (void? (cond))
#t

Infix to Prefix conversion scheme

I'm trying to figure out how to convert an infix expression to prefix in Scheme.
I found this post which does what I want but in the opposite direction. What changes when going from infix->prefix instead of prefix->infix?
Edit: I forgot to mention I need to account and handle for variables. For example the input
'(2 + 3 * a ^ 5 + b)
It's rather trivial to modify the algorithm you link to:
(define (infix->prefix lst)
(cond
((list? lst)
(unless (= 3 (length lst)) (error "not 3 elements"))
(let ((operand1 (car lst))
(operator (cadr lst))
(operand2 (caddr lst)))
(list operator
(infix->prefix operand1)
(infix->prefix operand2))))
(else lst)))
Testing:
> (infix->prefix '(1 + 2))
'(+ 1 2)
> (infix->prefix '(1 + (2 * 3)))
'(+ 1 (* 2 3))
> (infix->prefix '((1 / 4) + (2 * 3)))
'(+ (/ 1 4) (* 2 3))
This is not a general algorithm though; if you need something more elaborate then please show some examples of conversions you need to do.
EDIT Here's an example code that works for longer expressions but doesn't implement operator precedence:
(define (infix->prefix lst)
(if (list? lst)
(if (null? (cdr lst))
; list with one element -> return element
(infix->prefix (car lst))
; list with more than one element
(list (cadr lst)
(infix->prefix (car lst))
(infix->prefix (cddr lst))))
; not a list -> return element
lst))
Testing:
> (infix->prefix '(2 + 3 * a ^ 5 + b))
'(+ 2 (* 3 (^ a (+ 5 b))))

Adding "Simply Scheme" language to DrRacket

I want to work through this book: http://www.eecs.berkeley.edu/~bh/ss-toc2.html. But I'm having trouble to get the "Simply Scheme" language working. The code won't run.
#lang planet dyoo/simply-scheme:2
(parse ’(4 + 3 * 7 - 5 / (3 + 4) + 6))
I keep getting the following error message: "parse: unbound identifier in module in: parse".
Take a look at this page, it has complete instructions. Simply do this:
#lang racket
(require (planet dyoo/simply-scheme:2:2))
Also be aware that the ’ character is incorrect, for quoting use ', this probably happened because you copy-pasted code with wrong typesetting.
And of course, after the above is done, you have to define the procedures explained in chapter 18, they're not defined in the package you just imported! this will work for sure:
(define (parse expr)
(parse-helper expr '() '()))
(define (parse-helper expr operators operands)
(cond ((null? expr)
(if (null? operators)
(car operands)
(handle-op '() operators operands)))
((number? (car expr))
(parse-helper (cdr expr)
operators
(cons (make-node (car expr) '()) operands)))
((list? (car expr))
(parse-helper (cdr expr)
operators
(cons (parse (car expr)) operands)))
(else (if (or (null? operators)
(> (precedence (car expr))
(precedence (car operators))))
(parse-helper (cdr expr)
(cons (car expr) operators)
operands)
(handle-op expr operators operands)))))
(define (handle-op expr operators operands)
(parse-helper expr
(cdr operators)
(cons (make-node (car operators)
(list (cadr operands) (car operands)))
(cddr operands))))
(define (precedence oper)
(if (member? oper '(+ -)) 1 2))
(define (compute tree)
(if (number? (datum tree))
(datum tree)
((function-named-by (datum tree))
(compute (car (children tree)))
(compute (cadr (children tree))))))
(define (function-named-by oper)
(cond ((equal? oper '+) +)
((equal? oper '-) -)
((equal? oper '*) *)
((equal? oper '/) /)
(else (error "no such operator as" oper))))
(parse '(4 + 3 * 7 - 5 / (3 + 4) + 6))
=> '(+ (- (+ (4) (* (3) (7))) (/ (5) (+ (3) (4)))) (6))
(compute (parse '(4 + 3 * 7 - 5 / (3 + 4) + 6)))
=> 30 2/7
There is also a module allowing you to run "Simply Scheme" here:
https://gist.github.com/alexgian/5b351f367169b40a4ad809f0bb718e1f
You can just run it and then type your code in interactively, no need for an installation like the Planet/dyoo code mentioned above.
Should you wish to, though, you can also install it, so that all you have to do then is to prefix any program with #lang simply-scheme and it will work.
Instructions for how to do so can be seen here:
https://groups.google.com/forum/#!topic/racket-users/jHPtw3Gzqk4
in the message by Matthew Butterick, June 4 2018.
This version takes care of some stuff not done the dyoo code, for instance
> (first 'american)
'a
> (first 'American)
"A"
> (every butfirst '(AmericAn Legacy CODE))
'("mericAn" egacy "ODE")
I.e. incorrect mixing of strings and symbols, instead of
> (first 'american)
a
> (first 'American)
A
> (every butfirst '(AmericAn Legacy CODE))
(mericAn egacy ODE)
as it should be.
The dyoo implementation might be more complete for docs, etc, though
However, as noted in the answer above, you will still have to enter the code for the parse function yourself, as this was the intention of the authors.
I had to revert to DrRacket 5.4.1 in order to get both Simply Scheme and SICP to work.

What is wrong with my scheme code?

The function I wrote for SICP 2.20 is:
(define (same-parity x . y)
(if (null? (car y)
'()
(if (= (even? (car y)) (even? x))
(cons (car y) (same-parity (cons x (cdr y))))
(same-parity (cons x (cdr y))))))
And then I try to call it with
(same-parity 1 2 3 4 5 6 7)
The error I get is:
"The object #t, passed as the first argument to integer-equal? is not the correct type."
I thought that equal works with #t and #f...
An example of code I found online is the following, I ran it and it works. But, what am I doing wrong?
(define (same-parity a . rest)
(define (filter rest)
(cond ((null? rest) '())
((= (remainder a 2) (remainder (car rest) 2))
(cons (car rest) (filter (cdr rest))))
(else
(filter (cdr rest)))))
(filter (cons a rest)))
The = procedure accepts numbers. But even? returns a boolean not a number.
Use equal? instead of =.
equal? works with booleans.
For instance at the REPL:
> (even? 2)
#t
> (= (even? 2) (even? 2))
=: expects type <number> as 1st argument, given: #t; other arguments were: #t
> (equal? (even? 2) (even? 2))
#t

Resources