2016-12-05 4 views
3

私はY連結子について説明したthisの記事を見つけました。コードはSchemeにありますが、私はCommon Lispを使って作業しようとしています。Common Lispで変数の関数を定義して使用する

しかし、SchemeからCommon Lispへの翻訳には問題があります。 Schemeは、関数と(その他の)変数の両方に単一の名前空間を使用しますが、Common Lispは関数と変数に異なる名前空間を使用します。この違いを解決してCommon Lispコードを動作させるには?

Schemeコード

ここでは、チュートリアルからいくつかのSchemeコードです。

(define (factorial n) 
    if (= n 0) 
    1 
    (* n (factorial (- n 1))))) 

し、この中にそれを変換します:著者は階乗関数を定義初めに

:のでそれはスキームが何をするかだ(作者によれば)

(define factorial 
    (lambda (n) 
    (if (= n 0) 
     1 
     (* n (factorial (- n 1)))))) 

スキームは、最初の定義を評価する前に、最初の定義を に変換するだけです。したがって、Schemeのすべての関数は実際にはラムダ の式です。

Common Lispの

Iは、第二の第一形態からこの移行を模倣するCommon Lispの上記断片の両方を書き換えることを試みました。しかし、CLにはdefineはなく、どちらも単一の名前空間を持っていません。だから私はそれを回避しようとしました。 Common Lispでは最初のスキームの定義を書き換え

は簡単だった:2番目の定義にこれを翻訳

(defun factorial (n) 
    (if (= n 0) 
     1 
     (* n (factorial (- n 1))))) 

しかし、(私には)少しトリッキーでした。私はこれを次のように翻訳しました:

(setf (symbol-function 'factorial) 
    (lambda (n) 
    (if (= n 0) 
     1 
     (* n (factorial (- n 1)))))) 

これは悪いやり方ですか?それは動作しているようだが、コンパイラは私にスタイル警告を与える:未定義関数:階乗。

答えて

3

は、いくつかの点では、より多くのこのようなものです:

(setf (symbol-function 'factorial) 
     (labels ((factorial (n) 
       (if (= n 0) 
        1 
        (* n (factorial (- n 1)))))) 
     #'factorial)) 

LABELSは、ローカル機能factorialを定義します。ローカル関数factorialの定義の中では、factorialへの呼び出しがその関数にあります。次に、この関数をラベル式から返します。したがって、再帰呼び出しは未定義関数ではない再帰関数を定義することができます。

Common Lispの実装を見ると、DEFUNはしばしば名前のついたラムダ関数のような移植不可能な構造に拡張されていることがわかります。さらに、DEFUNにはコンパイル時の副作用もあります。

2

変換は共通リストには意味がありません。

CL defunは通常、単なる(setf fdefinition)よりはるかに多くを行います。

(macroexpand-1 '(defun foo (a b c) (bar c a b)))を評価すると分かります。

本当の質問は - なぜこれをやろうとしているのですか?

+0

私はコードを読むだけではなく、自分でコードを入力するほうが簡単です。おそらくこの場合、これはSchemeとCommon Lispの違いのために最善の考えではありません。 – Frank

1

私が正しく理解している場合、あなたの質問の主な理由は、"Lisp-1" and a "Lisp-2"の間の翻訳です。

Schemeは "Lisp-1"です - それは関数と変数の両方のための単一の名前空間を持っています。一方、Common Lispは "Lisp-2"です - 関数と変数のために別々の名前空間を持っています。

方式では、あなたは

(define foo (lambda (...) ...)) 

を書くことができ、その後のようなfooを呼び出す:私たちは、同様のCommon Lispでまったく同じ方法でfooを定義することができ

(foo ...) 

が、我々はしようとした場合その構文を使用してfooとコールすると、プログラムがクラッシュします。これはfoo変数名前空間にあり、関数名前空間ではないためです。

我々はfooを呼び出すためにfuncallを使用することによってこの問題を回避することができます

(funcall foo ...) 

簡単な紹介です。 のページFunctionsには、役に立つと思われる追加情報があります。

+0

はい、異なる名前空間のアプローチが問題です。私は値のセルに関数を格納し(そして 'funcall'で呼び出す)、Rainerの解法を使うかどうかを決める必要があります。 OPに示す遷移のみが最終的にほぼ-要因 (ラムダ(F) (ラムダ(N) (IF(= N 0) 1(定義( 'もたらす遷移の長いシリーズの最初のものです(λ(x(x)))))))))))))))))))))) )(階乗(Yのほぼ階乗)を定義する) ')。 – Frank

+0

@フランク、右。 Y-コンビネータは、関数をパラメータとして渡し、その関数を適用することを含む。だから私はあなたがそこに着くかどうかにかかわらず、あなたが 'funcall'を必要とすると思います。 –

関連する問題