2016-08-23 26 views
6

私はPaul GrahamによってLispのRootsを読んでいましたが、lispの機能は、この7つの基本関数の組み合わせで構築できると主張しています:quote、atom、eq、cond、cons 、car、cdr。lispのカスタム '+'(合計)関数

質問:Lispの方言は、本当にそれらの関数にのみ基づいていますか?前述の7つのプリミティブ関数を使って、どのように 'sum'または 'plus'関数を定義できますか?例えば私たち独自の(+ 1 2)関数

注:私はLispにとってはまったく初心者ですが、その言語についても非常に興奮し始めています。この質問の目的は純粋に真の関心です。

+0

これらの7つの関数を持つLispには数字はありません。 1と2はありません。したがって(プラス1 2)は機能しません。 –

+2

これは1: '(())'です。これは2: '(()())'です。 –

答えて

12

著者はTuring AwardとLispの発明者であるJohn McCarthy “Recursive Functions of Symbolic Expressions and Their Computation by Machine”によって1960年に書かれた非常に有名な論文を指します。彼はLispのセマンティクスを新しい計算形式チューリングマシンの電源が入っています。

マッカーシーは、グラハムが言及した7つのプリミティブ関数のみを使用して完全に記述することができる、言語のための通訳を記述しています(そしてLisp 1.5 Manual)。

この言語は、主に記号計算に費やされ、論文に示されているインタプリタは、原子やペアとは異なる数や他のデータ型に頼らずに、計算だけに関係していました。

グラハム氏は、LispのRootの11ページの注釈で「McCarthyの1960年のLispで算術演算を行うことは可能です。 nのリストで、数字を表す数字はn "です。したがって、合計を実行することは、2つのリストを追加することと単純に等価です。

もちろん、この方法は非常に非効率的です。他の計算形式との等価性を示すためにのみ表示され、実際のインタプリタ/コンパイラの整数は通常通り表現され、通常の演算子を持ちます。

+0

Lisp 1.5には数字がありました。 24ページ(PDFの32)@Sylwester – Sylwester

+0

を参照してください。そうです。私は、1.6の「ユニバーサルLISP関数」(PDFの10-14ページ)のセクションを参照していました。ここでは、Lispの普遍的な関数、つまりメタ演算子であり、後で紹介する数値に関係なく定義されています「本当の」言語で書かれています。 – Renzo

3

私が覚えている限り、リストネストレベルを使用してこれを行う方法もありました(本当に覚えていない、どこで)。 ()から始まり、(()) == 1などとなる。そして、あなたは単にcarとしてlistとしてincdecを定義することができます。

CL-USER> (defun zero? (x) (eq() x)) 
ZERO? 

CL-USER> (zero? nil) 
T 

CL-USER> (zero? 1) 
NIL 

CL-USER> (defparameter *zero*()) 
*ZERO* 

CL-USER> (defun inc (x) (list x)) 
INC 

CL-USER> (defun dec (x) (car x)) 
DEC 

CL-USER> (defun plus (x y) 
      (if (zero? y) x (plus (inc x) (dec y)))) 
PLUS 

CL-USER> (plus *zero* (inc (inc *zero*))) 
((NIL)) 

CL-USER> (defparameter *one* (inc *zero*)) 
*ONE* 

CL-USER> (defparameter *two* (inc *one*)) 
*TWO* 

CL-USER> (defparameter *three* (inc *two*)) 
*THREE* 

CL-USER> (plus *two* *three*) 
(((((NIL))))) 

CL-USER> (equal *two* (dec (dec (dec (plus *two* *three*))))) 
T 
3

TL。 DR:いいえ。現代のlispシステムは、最初のlispよりも多くのプリミティブを持ち、新しいプリミティブデータタイプごとに新しいプリミティブが必要です。

最初のLispには数字はありませんでしたが、完全にチューリングしていました。つまり、他の言語でも可能な計算を行うことができますが、実用的ではありません。数は模倣するのが難しくありませんでしたが、計算は遅かったです。今日、Lisp 1.5より前の遅い算術に関するルーマーがあります。

私が初めてのインタプリタを作ったとき、私は数字を気にすることができませんでした。それは通訳の興味深い面ではありません。私は、一例としてfibonacci実装がなかった、これは次のように、それがどのように見えるかです:

;; This is NOT Common Lisp code. It's Zozotez 
(setq + (lambda (x y) 
    (if x (cons (car x) 
       (+ (cdr x) y)) 
     y))) 

(setq - (lambda (z w) 
    (if w (- (cdr z) 
      (cdr w)) 
     z))) 

(setq fibonacci 
    (lambda (n a1 a2) 
    (if n 
     (fibonacci (- n '(1)) 
        a2 
        (+ a2 a1)) 
     a1))) 

(fibonacci '(1 1 1 1 1 1 1 1 1)() '(1)) 
; ==> (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) 

ない数字!(1は私の言葉ではシンボルなので、引用符で囲む必要があります。そうでなければ、変数のように評価されます)

代替番号システムとして、私は位置付けシステムを実装しました。追加/乗算などのために使用されます。おそらく、長さnの格子よりも速いが、作るのがより複雑です。

Lispにクロージャがある場合、教会の数字を使うことができます。ラムダ計算と同じものを使うと、クロージャだけで何かを計算することができます。プリミティブが1つだけ必要です(lambda)。 (やはり、最も簡単なものではない)