所以我得到了这个代码:
#lang pl
#| BNF for the AE language:
<AE> ::= <num>
| { + <AE> <AE> }
| { - <AE> <AE> }
| { * <AE> <AE> }
| { / <AE> <AE> }
|#
;; AE abstract syntax trees
(define-type AE
[Num Number]
[Add AE AE]
[Sub AE AE]
[Mul AE AE]
[Div AE AE])
(: parse-sexpr : Sexpr -> AE)
;; to convert s-expressions into AEs
(define (parse-sexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(list '+ lhs rhs)
(Add (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '- lhs rhs)
(Sub (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '* lhs rhs)
(Mul (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '/ lhs rhs)
(Div (parse-sexpr lhs) (parse-sexpr rhs))]
[else
(error 'parse-sexpr "bad syntax in ~s" sexpr)]))
(: parse : String -> AE)
;; parses a string containing an AE expression to an AE AST
(define (parse str)
(parse-sexpr (string->sexpr str)))
(: eval : AE -> Number)
;; consumes an AE and computes the corresponding number
(define (eval expr)
(cases expr
[(Num n) n]
[(Add l r) (+ (eval l) (eval r))]
[(Sub l r) (- (eval l) (eval r))]
[(Mul l r) (* (eval l) (eval r))]
[(Div l r) (/ (eval l) (eval r))]))
(: run : String -> Number)
;; evaluate an AE program contained in a string
(define (run str)
(eval (parse str)))
您可以使用run (+ 3 5)
进行测试和运行IS,您将获得8。
我的任务是更改代码,以便我可以做run (3 + 5)
所以我将自己构建树的 parse-sexpr 函数更改为:
(: parse-sexpr : Sexpr -> AE)
;; to convert s-expressions into AEs
(define (parse-sexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(list lhs '+ rhs)
(Add (parse-sexpr lhs) (parse-sexpr rhs))]
[(list lhs '- rhs)
(Sub (parse-sexpr lhs) (parse-sexpr rhs))]
[(list lhs '* rhs)
(Mul (parse-sexpr lhs) (parse-sexpr rhs))]
[(list lhs '/ rhs)
(Div (parse-sexpr lhs) (parse-sexpr rhs))]
[else
(error 'parse-sexpr "bad syntax in ~s" sexpr)]))
我仍然可以编译代码,但是如果我这样做run (+ 5 3)
我会得到 8,如果我尝试run (5 + 3)
我会得到:
类型检查器:无法应用正字节类型的表达式,因为 它不是以下函数类型:(5 + 3(
为什么会这样?
这是一个关于什么是类型球拍中的表达式与什么是您的语言中的表达式的问题。在您的语言中,(5 + 3)
是一个表达式,但在键入的球拍中,它是一个类型错误。因此,您需要将(5 + 3)
表示为类型化球拍中的数据。
正如@soegaard指出的那样,一种常见的方法是在其前面放一个quote
,如下所示: '(5 + 3)
.虽然我讨厌这样写。它到底是什么,是(list 5 '+ 3)
.因此,您可以将其传递给新的parse-sexpr
函数以获取
> (parse-sexpr (list 5 '+ 3))
- : AE
(Add (Num 5) (Num 3))
然后,您可以将该值传递给eval
函数以获取
> (eval (Add (Num 5) (Num 3)))
- : Number
8
共同组成:
> (eval (parse-sexpr (list 5 '+ 3)))
- : Number
8
但是你的run
函数接受一个字符串,把它传递给string->sexpr
然后传递给parse-sexpr
,然后是你的eval
函数。所以你可能一直想这样做:
> (eval (parse-sexpr (string->sexpr "{5 + 3}")))
- : Number
8
> (run "{5 + 3}")
- : Number
8
假设string->sexpr
采用这样的大括号表达式。您正在做的是 (run (5 + 3))
,它将(5 + 3)
视为键入的球拍表达式。你想要的是(run "{5 + 3}")
,它将(5 + 3)
视为你的语言中的表达式,它表示为类型化球拍中的数据。
你偶然写的吗
(run (+ 5 3))
而不是
(run '(+ 5 3))
?
如果你写(run (+ 5 3))
那么 Racket 将首先计算(+ 5 3)
,然后调用 (run 8)
。如果你写(run (5 + 3))
那么 Racket 将尝试评估(5 + 3)
,这给出了你看到的错误:数字5
不是函数类型,所以它不能像(5 ...)
那样使用。