1

スキームでインタープリターを実装しようとしています。今のところ、その一部を実装しましたが、「if」ステートメントに問題があります。文法は次のとおりです。

<s6> -> <expr>
        | <define>

<define> -> ( define IDENT <expr> )

<expr> -> NUMBER
          | IDENT
          | <if>

<if> -> ( if <expr> <expr> <expr> )

これまでに書いたコードは次のとおりです。

(define get-operator (lambda (op-symbol)
(cond
    ((equal? op-symbol '+) +)
    ((equal? op-symbol '-) -)
    ((equal? op-symbol '*) *)
    ((equal? op-symbol '/) /)
    (else (error "s6-interpret: operator not implemented -->" op-symbol)))))


(define if-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'if) (= (length e) 4))))

(define define-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'define) (symbol? (cadr e)) (= (length e) 3))))


(define get-value (lambda (var env)
(cond
    ((null? env) (error "s6-interpret: unbound variable -->" var))
    ((equal? (caar env) var) (cdar env))
    (else (get-value var (cdr env))))))


(define extend-env (lambda (var val old-env)
(cons (cons var val) old-env)))


(define repl (lambda (env)
(let* (
    (dummy1 (display "cs305> "))
    (expr (read))
    (new-env (if (define-stmt? expr)
                (extend-env (cadr expr) (s6-interpret (caddr expr) env) env)env))
    (val (if (define-stmt? expr)
                (cadr expr)
                (s6-interpret expr env)))
    (dummy2 (display "cs305: "))
    (dummy3 (display val))
    (dummy4 (newline))
    (dummy4 (newline)))
(repl new-env))))


(define s6-interpret (lambda (e env)
(cond
    ((number? e) e)
    ((symbol? e) (get-value e env))
    ((not (list? e)) (error "s6-interpret: cannot evaluate -->" e))
    (if-stmt? e) (if (eq? (cadr e) 0) (map s6-interpret (cadddr e)) (map s6-interpret(caddr e))))
    (else
        (let ((operands (map s6-interpret (cdr e) (make-list (length (cdr e)) env)))
                (operator (get-operator (car e))))
            (apply operator operands))))))


(define cs305-interpreter (lambda () (repl '())))

define ステートメントはうまく機能します。私のコードには、いくつかの基本的な数学演算子の実装も含まれていますが、それらは無視できます。私の問題は、実装した「if」ステートメントが期待どおりに機能しないことです。「(if 1(+ 2 5)9)」と書くと(+ 2 5)と出力されますが、実際には2 + 5である7と出力したいのです。私の再帰に問題があると思います。誰でもこれで私を助けることができますか?

ありがとうございました

4

1 に答える 1

3

if ステートメントは長さ 3 ではなく 4 のリストであるため、if ステートメント用に作成したコードはトリガーされません。

(define if-stmt? (lambda (e)
  (and (list? e)
       (equal? (car e) 'if)
       (= (length e) 3))))


> (length '(if condition then-clause else-clause))
4
> (if-stmt? '(if condition then-clause else-clause))
#f

おそらく、シンボル「if」で始まるリストを if ステートメントとして受け入れる方が理にかなっているでしょう。正当な長さを持たない場合、それはif 文が壊れていることを意味するだけで、完全に別のものであるということではありません (インタプリタを書いている言語が、この点で Lisp にとって珍しいものでない限り)。

この場合、再帰を使用していないという点で、再帰にも実際に何か問題があります。いつ if-stmt? トリガー、あなたは s6-interpret を再度呼び出していません。以下は正しいに近いでしょう:

((if-stmt? e)
 (s6-interpret
  (if (eq? (cadr e) 0)
     (cadddr e)
     (caddr e))
  env))

if ステートメントなど、実装には他にも不規則性があることに注意してください。たとえば、「0」が false と評価されることは慣習的ではなく、#f が true と評価されることは確かに非常に型破りです。

スキームの実装が実際に何を行っているかを確認して、何が慣習的/正しいと見なされるかを確認してください。言語仕様については、比較的短くて読みやすいR5RSも参照できます。

コードの読みやすさに関するいくつかのヒント:

従来のインデントを使用する必要があります。これにより、コードが読みやすくなります。スキーム対応のエディターを使用している場合は、エディターがこれを支援してくれる可能性があります。たとえば、DrRacket では、行頭で「タブ」を押すだけで、この行が修正されます。必要に応じて改行を挿入する必要があります。

スキームには、特に関数を定義するための構文があります。これを使って。ラムダをシンボル名にバインドすることですべてを実装できると教えられた可能性があります。関数は特別なものではありません。これは重要な理論的ポイントですが、実際にこれを行うことはお勧めできません。以下は基本的に同等ですが、後者の方が短くて読みやすいです。

(define f (lambda (a b) (+ a b)))
(define (f a b) (+ a b))
于 2013-05-23T18:12:36.530 に答える