2017-09-26 16 views
1

私はSchemR言語を試してみるためにDrRacket環境を使用しています。これはなぜSchemeで評価されないのですか?

次のように私は合計+ 1を定義した:

(define sum+1 '(+ x y 1)) 

次の式は評価されない理由は、私が思っていた:

(let ([x 1] [y 2]) (eval sum+1)) 

をこれを行うことは、正しい値を返すのに対し:

(define x 1) 
(define y 2) 
(eval sum+1) 
+0

これは合理的に説明されています[ラケットガイド](https://docs.racket-lang.org/guide/eval.html)。 – molbdnilo

答えて

0

eval字句変数は同じ表現で作成された場合を除き、すべての語彙の変数では動作しませんが:

#!r7rs 
(import (scheme base) 
     (scheme eval)) 

(define env (environment '(scheme base))) 

(let ((x 10)) 
    (eval 'x env)) ; ERROR! `x` is not defined 

あなたはevalいつもあなたが環境のグローバルな束縛をトップレベルに起こっと考えることができます2番目の引数に渡します。あなたは、おそらくこのようなあなたの字句の環境から値を渡すことによって、それをだますことができます。

(eval '(let ((x 10)) 
     x) 
     env) ; ==> 10 


(let ((x 10)) 
    (eval `(let ((x ,x)) 
      x) 
     env) ; ==> 10 

をほとんどのScheme実装は、コードのローカル変数は、通常、割り当てられたスタックされている実行時まで。したがって、何かが、このコードを想像してみてください。また、あなたは、コーナーケースを作ることができます

(define (test 1 #f) ; indicates 1 argument, no rest 
    (display (ref 0)) ; fetches first argument from stack 
    (newline) 
    (eval 'v))  ; but what is v?, certainly not the first argument 

(define (test v) 
    (display v) 
    (newline) 
    (eval 'v)) 

は、実行時に、このになるかもしれません。突然変異を起こすとどうなりますか?

(define (test v) 
    (eval '(set! v 10)) 
    v) 

それはvが変異されることを明らかにしませんのでevalの構造は、ユーザの入力から来るかもしれない、それはコードがvは特別な必要があることを実行する前に知っておく必要がありますので、また多くのコンパイルスキームの実装が異なって変異した変数を処理するために必要(set! v 10)はデータベースまたはユーザーの入力に由来する可能性があるため、決定できません。したがって、ローカルバインディングを含まないことで、多くの問題を解決し、言語の最適化とコンパイルが容易になります。

マクロをファーストクラスのオブジェクトとして渡すことができるため、解釈できるのは、lisp言語だけです。これらの言語はコンパイル時に推論することは不可能です。

0

letのコマンドが機能しない理由は、letは、ローカル変数を作成します。つまり、作成する変数には、どこからでもアクセスすることはできません。つまり、letのbody引数からのみアクセスできます。あなたの例では

、あなたが定義した:

(define sum+1 '(+ x y 1)) 

を次にあなたがこれを命じ:

(let ([x 1] [y 2]) (eval sum+1)) 

xyのみの中、eval文で定義されていませんされているので、これは動作しません。手順sum+1。これは直感的ではないように思えるかもしれませんが、他の入力で多くのエラーを防ぐことができます。

あなたの第二の例は以下のとおりであった:

(define x 1) 
(define y 2) 
(eval sum+1) 

xyグローバルに定義されているので、これは作品を行います。これはどこにでも何でもアクセスできることを意味します。それらはsum+1定義に適用され、印刷することができます。ご質問やご意見をお寄せください。

+0

答えにはありがとうございます。だから、 'eval'は呼び出されたスコープ内の定義を見ることはできませんが、グローバルスコープ内の定義のみを見ることができます。他のプロシージャがグローバルスコープにオーバーライドするローカルスコープにアクセスできるので、eval自体はプロシージャであり、他のすべてのプロシージャのように動作する特別なフォームではないので、この動作は奇妙です。この行動を正当化する理由はありますか? –

+0

私は、evalが他のプロシージャのように動作しない理由について完全にはわかりませんが、ここで私の推測は最高です:evalは何かを評価するよう求めている特定の関数なので、 )、 "この問題を解決するために私にはどんな情報がありますか?"この問題を解決するために私に与えられた情報は?つまり、グローバルに呼ばれる手続きとは対照的に、それに与えられた具体的な指示が必要です。 –

+1

'eval' *がレキシカルバインディングをどのように見ることができるかについて考えてみる価値があります:特にどのように'(eval()読んで)) '仕事?コンパイラはどのように動作しますか? – tfb

関連する問題