1

The Little Schemerで遊んでいて、作業しながらアイデアを試しています (すべてがうまくいくわけではありません)。ちょうど今、私は第 6 章 (ヘルパー関数を紹介する場所) にいて、一歩が手の届くところにあると感じています。その一歩を踏み出す方法がわかりません。

本のコードは次のとおりです。

(define (^ b e) (expt b e))

(define (x a b) (* a b))

(define value-i
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (car (cdr nexp)) '+) (+ (car nexp) (value-i (caddr nexp))))
      ((eq? (car (cdr nexp)) 'x) (x (car nexp) (value-i (caddr nexp))))
      (else
        (^ (car nexp) (value-i (caddr nexp))))
      )))

次のヘルパーが定義されています。

(define (operator-i aexp) (car (cdr aexp)))
(define (firstSubExp-i aexp) (car aexp))
(define (secondSubExp aexp) (caddr aexp))

そして、この単純化が行われます:

(define value-i2
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (operator-i nexp) '+) (+ (firstSubExp-i nexp) 
                                     (value-i2 (secondSubExp nexp))))
      ((eq? (operator-i nexp) 'x) (x (firstSubExp-i nexp) 
                                     (value-i2 (secondSubExp nexp))))
      (else
        (eq? (operator-i nexp) '^) (^ (firstSubExp-i nexp) 
                                      (value-i2 (secondSubExp nexp))))
      )))

が見ることができる単純化は、すべてが有効であると仮定しているため、ボイラープレートnexpを繰り返す必要がないということです。((eq? (operator-i nexp) ...

次のようなものが機能するはずです。

(define value-i3
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      (else
        ((operator-i nexp) 
         (firstSubExp-i nexp) 
         (value-i3 (secondSubExp nexp))))
      )))

...そうでないことを除いて。Exception: attempt to apply non-procedure ...(+、x、^ のいずれか) でエラーになります。

で関数を呼び出そうとしていることを認識しないことが問題であることがわかります(operator-i nexp)

返す関数を適用したいことをインタプリタに明確にするにはどうすればよい(operator-i nexp)ですか?

他のヒントも大歓迎です(私はプチシェスキームを使用しています)。

4

2 に答える 2

4

残念ながら、プロシージャ オブジェクトではなくシンボルを返すvalue-i3ため、機能しません。(operator-i nexp)と の違いに注意して'+ください+

それを回避する簡単な方法はありません (除外した場合eval、これは総体的で推奨されません)、alist を使用してシンボルをプロシージャにリンクする (またはSylwester の回答で言及されているように or を使用する)case以外は:cond

(define symbol->procedure
  (let ((opmap `((+ ,+)
                 (x ,x)
                 (^ ,^))))
    (lambda (x)
      (cond ((assq x opmap) => cadr)
            (else #f)))))

次にsymbol->procedure、シルウェスターの答えと同じ方法を使用します。

準引用符が読みにくい場合は、listand をcons直接使用できます。

(define symbol->procedure
  (let ((opmap (list (cons '+ +)
                     (cons 'x x)
                     (cons '^ ^))))
    (lambda (x)
      (cond ((assq x opmap) => cdr)
            (else #f)))))

OPは、などの詳細情報を求めたassqので、投稿を直接更新すると思いました。基本的に、to 、またはそれ以外の(assoc key alist)最初のアイテムを返しますalist。andは類似していますが、andを比較演算子として使用します。したがって、ここにサンプル実装があります (R7RS/SRFI-1 セマンティクスを使用):carequal?key#fassqassvassoceq?eqv?

(define (find pred lst)
  (cond ((null? lst) #f)
        ((pred (car lst)) (car lst))
        (else (find pred (cdr lst)))))

(define assoc
  (case-lambda
    ((key alist equal?)
     (find (lambda (x)
             (equal? key (car x)))
           alist))
    ((key alist)
     (assoc key alist equal?))))

(define (assq key alist)
  (assoc key alist eq?))

(define (assv key alist)
  (assoc key alist eqv?))
于 2013-12-26T21:47:40.773 に答える