Orie Stone
Orie Stone

Reputation: 49

Issues with evaluating expressions from user input

I'm trying to make a recursive definition that reads and execute user expressions, such as (3 + 5). Everything is working, except of one problem with the arithmetic symbol.

I managed to replicate the error in a simpler example:

(define v '(1 + 3))

((cadr v) 2 4)

The (cadr v) is the + symbol, but for some reason the procedure can't be executed on the two arguments that followed. Am I missing something?

Upvotes: 4

Views: 419

Answers (4)

soulcheck
soulcheck

Reputation: 36767

I think that's because

(cadr v)

returns '+ not + (literal + not a + function).

You need to evaluate it before applying it to arguments.

This should work:

((eval (cadr v)) 2 4)
 ^evaluates the '+ to +

edit This worked in racket in interactive mode.

I'm not really sure what's the difference, but made it work in r5rs mode in racket (a script):

#lang r5rs

;required by r5rs
(define user-initial-environment (scheme-report-environment 5))

(define v '(1 + 2))

;eval expects a quoted expression
;(it seems that if it's a function it has to have arguments too)
;and evaluation environment.
((eval (cadr v)  user-initial-environment) 2 4)

Upvotes: 3

John Clements
John Clements

Reputation: 17203

As others have pointed out, the problem is that the list you've constructed contains the symbol plus, rather than the function plus.

At its heart, this is the same reason that '(a b) returns a list of two symbols, rather than signalling an unbound identifier error; the quote starts a term in a "data language" where legal identifiers are interpreted as symbols, rather than as variable references.

The question, of course, is what you should do about it. Some here have suggested using 'eval'; this is probably a bad idea, for reasons that I think Matthew Flatt captures elegantly in his blog post on the topic.

Instead, you should probably write a simple mapping function. Here's the way I'd write it. If you use my code in an assignment, be sure to credit me :).

#lang racket

;; a mapping from symbols to operators
(define operator-hash
  (hash '+ +
        '- -
        '* *))
;; ... and whatever other operators you want.

;; example of using it:
(hash-ref operator-hash '+) ;; ==> +

Upvotes: 1

gcbenison
gcbenison

Reputation: 11963

You can do it this way with eval in Guile:

(define (infix-eval v)
   (eval (list (cadr v)(car v)(caddr v))
         (interaction-environment)))

> (infix-eval '(1 + 2))
3

Rather than using interaction-environment, you could supply another environment for evaluation, where you could also define some other symbols not found in standard Scheme, so that expressions like (7 % 3) and (2 ^ 6) would also work.

Upvotes: 0

Óscar López
Óscar López

Reputation: 236004

Try this:

(define v '(1 + 3))

(let ((operator (eval (cadr v)))
      (operand1 (car v))
      (operand2 (caddr v)))
  (apply operator (list operand1 operand2)))

Upvotes: 0

Related Questions