Post on 26-Dec-2019
2012/05/14
言語処理系構成論(5)Lisp処理系とLispプログラミング(1)
岡山大学大学院自然科学研究科渡邊誠也
1
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
はじめに! 言語処理系(解釈系,翻訳系)の動作,仕組みを
Lisp(Scheme)で記述することで理解を深める.! 準備としてLisp(Scheme)について学ぶ
! Lispの概要! Schemeの基本
! 式! 名前と環境! 組合せの評価,合成手続き,手続き作用と置換えモデル! 条件式と述語! 内部定義とブロック構造! 高階手続き! lambda,局所変数
2
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
参考文献
3
! H. Abelson and G. J. Sussman, with J. Sussman: Structure and Interpretation of Computer Programs (2nd ed.), The Massachusetts Institute of Technology, 1996! Web(↓)にfull text がある! http://mitpress.mit.edu/sicp/full-text/book/
book.html ! (Wizard Book と呼ばれている)
! R. Kelsey, et al. (editors): Revised5 Report on the Algorithmic Language Scheme,1998! Schemeの仕様書! http://schemers.org/Documents/Standards/R5RS/
r5rs.pdf(R6RS, 2007 http://www.r6rs.org/final/r6rs.pdf)
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
計算プロセス! 計算プロセス(computational process)
! 計算機の中に住む抽象的な存在! 進行しながらデータ(もう1つの抽象的な存在)を操作
! プロセスの進行...プログラムの指示に従う! プログラミング...プロセスに対する指示の作成
! われわれの呪文で計算機の霊に魔法をかける (we conjure the spirits of the computer with our spells.)
! プロセスに魔法をかけるのに使うプログラム...魔法使いの呪文! プロセスに実行させたい仕事を示すために,プログラムはプログラミング言語の記号式で注意深く構成されている
! プログラムを精細かつ正確に実行! 魔法の結果を理解し,予測する技法を学ばねばならない
4
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
LispとLispの処理系! Lisp
! 1950年代の終わり頃,発明! John McCarthy, “Recursive Functions of Symbolic Expressions and Their
Computation by Machine,’’ Communications of the ACM, vol. 3, no. 4, pp.184 -195, 1960! 計算モデルである「再帰方程式(recursion equations)」というある種の論理表現についての推論の形式化として発明
! Lispの解釈系(interpreter)! Lisp言語で記述されたプロセスを実行する機械! 最初の解釈系
! MIT電子工学研究所の人工知能グループとMIT計算機センターの同僚や学生の助けを借りMcCarthyが実装
5
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
Lispによるプログラミング(続き)! Lisp処理系
! 初期の処理系: 試作的性格と記号処理重視のため数値計算は極めて非効率(Fortran比)
! プログラムを機械コードに翻訳する処理系の開発によって効率化! 特定の応用には有効に利用されてきた
! 効率があまり要求されない応用(e.g. 操作系のシェル言語,エディタやCADシステムの拡張言語)
6
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
なぜLispを使うのか?! Lispの独特な特徴
! プロセスの手続き(procedures)というLispによる記述自体がLispデータとして表現,処理できる
! 「受動的」なデータと「能動的」なプロセスを区別する伝統をぼやかす点に依存した強力なプログラム設計技法が使える → 手続きをデータとして扱えるLispの柔軟さ
! 手続きをデータとして表現できる能力! 他のプログラムをデータとして扱うプログラム(解釈系,翻訳系,i.e., 言語処理系)を書く優れた言語
7
本講義では,Lispの方言の1つである,Scheme を用いる
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
プログラムの要素! 強力なプログラミング言語
! 計算機に仕事のやり方を指示する手段以上のもの! 言語はプロセスに関する考えをまとめる枠組みとしても役立つ
! 強力な言語の3つのメカニズム! 基本式 (primitive expression) ...言語が関わる最も単純なものを表す! 組合せ法 (means of combination) ...より単純なものから合成物を作る! 抽象化法 (means of abstraction) ...合成物に名前をつけ単一のものとして扱う
! プログラミング! 2つの要素(手続きとデータ)を扱う
8
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
! Lispにおけるプログラム! 式を入力すると処理系は,その式を評価した結果を表示! 【例】
! 123! ! 123! (+ 12 34)! ! 46! (- 30 20)! ! 10
式(Expressions)
9
組合せ(combinations) ... 式の並びを括弧で囲んで手続きの作用を表現する式演算子(operator) ... 並びに左端の要素
被演算子(operands) ... 他の要素組合せの値は演算子が指定する手続きを,被演算子の値であるある引数(arguments)に作用させて得られる
前置記法(prefix notation)...演算子を被演算子の左に置く書き方
(利点1) 任意個の引数 (+ 1 2 3 4 5)
(利点2) 組合せの入れ子 (* (+ 1 2 ) (+ 3 4))
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
式の例
10
(+ (* 3 (+ (* 2 4) (+ 3 5))) (+ (- 10 7) 6))
(+ (* 3
(+ (* 2 4)
(+ 3 5)))
(+ (- 10 7)
6))
pretty print
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
名前と環境(Naming and Environment)! 名前(naming)
! オブジェクト(object)を値とする変数(variable)を識別するもの! Schemeでは,define を使って名前をつける! 【例】
! (define size 2)! size! ! 2! (* 5 size)! ! 10
! 環境(environment)! 解釈系において,値と記号の対応づけを保持するための記憶
11
size
2
*掛算を計算する手続き
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
組合せの評価(Evaluating Combinations)! 評価手順
1.組合せの部分式を評価2.最左部分式の値である手続き(演算子)を残りの部分式の値である引数(被演算子)に作用
! 再帰的: 組合せの各要素の評価プロセスの実行が必要
12
! 評価 (evaluation)! 数字列の値 → その数値! 基本演算子の値 → 対応する演算を実行する機械命令の列! その以外の名前の値 → その環境で名前と対応づけられたオブジェクト
(+ a 2)
3
(+ 1 2)
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
組合せの評価(続き)! 特殊形式(special forms)
! 一般的評価規則の例外! それ自身の評価規則をもつ! 【例】define
13
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
【例】「2乗」「何かを2乗するには,それにそれ自身をかける」
合成手続き(Compound Procedures)! 手続きの定義(procedure definitions)
! 合成演算に名前を対応付ける
14
(define (square x) (* x x))
には 2乗する 何かを かける それに それ自身を
(define (�name���formal parameters�) �body�)
手続き定義の一般形
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
合成手続き(続き)! 合成手続きの利用
15
(square 21)
441(square (+ 2 5))
49(square (square 3))
81
(define (sum-of-squares x y)
(+ (square x) (square y)))
! 他の手続きの組立て素材として利用
(sum-of-squares 3 4)
25
合成手続きは基本的手続きとまったく同様に利用可能
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
手続き作用の置換えモデル(The Substitution Model for Procedure Application)
16
(define (f a)
(sum-of-squares (+ a 1) (* a 2)))
(f 5)
(sum-of-squares (+ a 1) (* a 2))
(sum-of-squares (+ 5 1) (* 5 2))
(sum-of-squares 6 10)
(+ (square 6) (square 10))
(+ (* 6 6) (* 10 10))
(+ 36 100)
136
sum-of-squaresの本体を取り出し,仮パラメタx, yを6と10に置き換え
仮パラメタaを引数5で置き換え
組合せの評価
fの本体を取り出す
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
手続き作用の置換えモデル(The Substitution Model for Procedure Application)
16
(define (f a)
(sum-of-squares (+ a 1) (* a 2)))
(f 5)
(sum-of-squares (+ a 1) (* a 2))
(sum-of-squares (+ 5 1) (* 5 2))
(sum-of-squares 6 10)
(+ (square 6) (square 10))
(+ (* 6 6) (* 10 10))
(+ 36 100)
136
sum-of-squaresの本体を取り出し,仮パラメタx, yを6と10に置き換え
仮パラメタaを引数5で置き換え
組合せの評価
fの本体を取り出す
手続き作用の置換えモデル(substitution model)
...手続き作用の「意味」を定めるモデル
解釈系の実際の働きを述べるもではない!
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
条件式と述語(Conditional Expressions and Predicates)
! cond: 場合分け(case analysis)を記述する特殊形式
17
(define (abs x)
(cond ((> x 0) x)
((= x 0) 0)
((< x 0) (- x)))
|x| =
�⇤
⇥
x if x > 00 if x = 0
�x if x < 0
(cond (�p1� �e1�)
(�p2� �e2�)
…
(�pn� �en�))
条件式の一般形 節(clauses)
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
条件式と述語(Conditional Expressions and Predicates)
! cond: 場合分け(case analysis)を記述する特殊形式
17
(define (abs x)
(cond ((> x 0) x)
((= x 0) 0)
((< x 0) (- x)))
|x| =
�⇤
⇥
x if x > 00 if x = 0
�x if x < 0
(cond (�p1� �e1�)
(�p2� �e2�)
…
(�pn� �en�))
条件式の一般形
述語(predicate)
節(clauses)
値を真か偽と解釈する式
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
条件式と述語(Conditional Expressions and Predicates)
! cond: 場合分け(case analysis)を記述する特殊形式
17
(define (abs x)
(cond ((> x 0) x)
((= x 0) 0)
((< x 0) (- x)))
|x| =
�⇤
⇥
x if x > 00 if x = 0
�x if x < 0
(cond (�p1� �e1�)
(�p2� �e2�)
…
(�pn� �en�))
条件式の一般形
述語(predicate)
節(clauses)
値を真か偽と解釈する式
帰結式(consequent expression)
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
条件式と述語(続き)! 絶対値の手続きの別の記述方法
18
(if �predicate� �consequent� �alternative�)
if式の一般形
述語 帰結部 代替部
(define (abs x)
(cond ((< x 0) (- x))
(else x)))
! if式(特殊形式): 場合分けが2つの制限付き条件式
(define (abs x)
(if (< x 0)
(- x)
x))
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
条件式と述語(続き)! 論理合成演算
19
(and �e1� ... �en�)
(or �e1� ... �en�)
(not �e�)
式��e1� ... �en��を左から右へ1つずつ評価.ある式の評価結果が偽なら,and式の値は偽で残りの式は評価しない.全ての式が真と評価されたなら,and式の値は最後の式�en�の値
式��e1� ... �en��を左から右へ1つずつ評価.ある式の評価結果が真なら,or式の値はその式の値で残りの式は評価しない.全ての式が偽と評価されたなら,or式の値は偽
式�e�の評価結果が偽なら真,そうでなければ偽
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
条件式と述語(続き)! 論理合成演算
19
(and �e1� ... �en�)
(or �e1� ... �en�)
(not �e�)
式��e1� ... �en��を左から右へ1つずつ評価.ある式の評価結果が偽なら,and式の値は偽で残りの式は評価しない.全ての式が真と評価されたなら,and式の値は最後の式�en�の値
式��e1� ... �en��を左から右へ1つずつ評価.ある式の評価結果が真なら,or式の値はその式の値で残りの式は評価しない.全ての式が偽と評価されたなら,or式の値は偽
式�e�の評価結果が偽なら真,そうでなければ偽
and と or
部分式が必ずしもすべて評価されるわけでない! 特殊形式
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
例: Newton法による平方根! 計算手順
! 数 x の平方根の予測値yがあれば,y と x / y の平均値をとることで更によい(真の平方根に近い)予測値が得られる
20
予測値 商 平均値1 2/1 = 2 (1+2)/2 = 1.5
1.5 2/1.5 = 1.3333 1.4167
1.4167 1.4118 1.4142
1.4142 ... ...
√ 2
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
例: Newton法による平方根
21
f(x) = x2 � C
f �(x) = 2x
f(x) = 0
f �(x0) =�f(x0)x1 � x0
x1 = x0 �f(x0)f �(x0)
x1 =x0 + C/x0
2
x1 = x0 �x2
0 � C
2x0
x0 x1
x1 � x0
f �(x0)
f(x)
�f(x0)
x
方程式
における傾きx0
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
平方根を求めるプログラムsqrtの実装
22
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
(define (improve guess x)
(average guess (/ x guess)))
(define (average x y)
(/ (+ x y) 2))
(define (good-enough? guess x)
(< (abs (- (square guess) x)) 0.001))
(define (sqrt x)
(sqrt-iter 1.0 x))
予測値guessが十分なら,guessを返す.そうでないなら,より良い値を求めることを繰り返す
手続き呼出の機能があれば,特別な構文がなくても反復が実行可能!
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
内部定義とブロック構造(Internal definitions and Block Structure)
! ブロック構造(block structure): 定義の入れ子
23
(define (sqrt x)
(define (good-enough? guess x)
(< (abs (- (square guess) x)) 0.001))
(define (improve guess x)
(average guess (/ x guess)))
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
(sqrt-iter 1.0 x))
内部定義
sqrt の利用者にとっては,手続きsqrtが重要であり,sqrt-iterやgood-enough?, improveに関心はない
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
内部定義とブロック構造(続き)
24
(define (sqrt x)
(define (good-enough? guess)
(< (abs (- (square guess) x)) 0.001))
(define (improve guess)
(average guess (/ x guess)))
(define (sqrt-iter guess)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
(sqrt-iter 1.0))
x はsqrtの定義に束縛→内部手続きはxの有効範囲内になるので, xを内部手続きに明示的に渡す必要はない
xの有効範囲
静的有効範囲(lexical scoping)
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
高階手続き(Higher-order Procedures)! 手続きを扱う手続き
25
(define (sum-integers a b)
(if (> a b)
0
(+ a (sum-integers (+ a 1) b))))
(define (sum-cubes a b)
(if (> a b)
0
(+ (cube a) (sum-cubes (+ a 1) b))))
(define (pi-sum a b)
(if (> a b)
0
(+ (/ 1.0 (* a (+ a 2))) (pi-sum (+ a 4) b))))
aからbまでの整数の和
整数の3乗の和
11 · 3
+1
5 · 7+
19 · 11
+ · · · (= �/8)
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
高階手続き(Higher-order Procedures)! 手続きを扱う手続き
25
(define (sum-integers a b)
(if (> a b)
0
(+ a (sum-integers (+ a 1) b))))
(define (sum-cubes a b)
(if (> a b)
0
(+ (cube a) (sum-cubes (+ a 1) b))))
(define (pi-sum a b)
(if (> a b)
0
(+ (/ 1.0 (* a (+ a 2))) (pi-sum (+ a 4) b))))
aからbまでの整数の和
整数の3乗の和
11 · 3
+1
5 · 7+
19 · 11
+ · · · (= �/8)
(define (�name� a b) (if (> a b) 0 (+ (�term� a) (�name� (�next� a) b))))
b�
n=a
f(n) = f(a) + · · · + f(b)
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
高階手続き(続き)
26
(define (sum term a next b) (if (> a b) 0 (+ (term a) (sum term (next a) next b))))
(define (inc n) (+ n 1))
(define (sum-cubes a b)
(sum cube a inc b))
(define (identify x) x)
(define (sum-integers a b)
(sum identify a inc b))
(define (pi-sum a b)
(define (pi-term x)
(/ 1.0 (* x (+ x 2))))
(define (pi-next x)
(+ x 4))
(sum pi-term a pi-next b))
手続きを引数としてとる
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
Constucting Procedures Using lambda
! 手続きを作り出す特殊形式 lambda
27
(define (pi-sum a b)
(define (pi-term x)
(/ 1.0 (* x (+ x 2))))
(define (pi-next x)
(+ x 4))
(sum pi-term a pi-next b))
pi-next: 入力を4増やす
「入力を4増やして返す手続き」を直接指定する方法があると便利
(define (pi-sum a b)
(sum (lambda (x) (/ 1.0 (* x (+ x 2))))
a
(lambda (x) (+ x 4))
b))
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
lambda(続き)
28
(lambda (�formal-parameters�) �body�)
lambdaの一般形
(define (plus4 x) (+ x 4))
(define plus4 (lambda (x) (+ x 4)))
等価
define で定義される手続きと同じ.環境で名前と対応づけられていない点が異なる
plus4
(lambda (x) ...)
((lambda (x y z) (+ x y (square z))) 1 2 3)
! 12
演算子としても使える
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
局所変数(Local Variables)
29
f(x, y) = x(1 + xy)2 + y(1� y) + (1 + xy)(1� y)
a = 1 + xyb = 1� y
f(x, y) = xa2 + yb + ab
(define (f x y)
(define (f-helper a b)
(+ (* x (square a))
(* y b)
(* a b)))
(f-helper (+ 1 (* x y))
(- 1 y)))
補助手続きを使う方法
(define (f x y)
((lambda (a b)
(+ (* x (square a))
(* y b)
(* a b)))
(+ 1 (* x y))
(- 1 y)))
lambdaを使う方法
途中の値の名前(a, b)を使って書きたい
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
局所変数(Local Variables)
29
f(x, y) = x(1 + xy)2 + y(1� y) + (1 + xy)(1� y)
a = 1 + xyb = 1� y
f(x, y) = xa2 + yb + ab
(define (f x y)
((lambda (a b)
(+ (* x (square a))
(* y b)
(* a b)))
(+ 1 (* x y))
(- 1 y)))
lambdaを使う方法
途中の値の名前(a, b)を使って書きたい
(define (f x y)
(let ((a (+ 1 (* x y)))
(b (- 1 y)))
(+ (* x (square a))
(* y b)
(* a b))))
let による局所変数
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
局所変数(続き)
30
(let ((�var1� �exp1�)
(�var2� �exp2�)
…
(�varn� �expn�))
�body�)
letの一般形
�body��の中で��var1��は値�exp1��を持ち,��var2��は値�exp2��を持ち,...��varn��は値�expn��を持つとせよ
((lambda (�var1�... �varn�)
�body�) �exp1�
…
�expn�)
≡
解釈系に局所変数を用意する新しい機構が必要になるわけではない!
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
値として返される手続き(Procedures as Returned Values)
! 微分
31
Dg(x) =g(x + dx)� g(x)
dx g(x)
xdx
x + dx
g(x + dx)
(define (deriv g)
(lambda (x)
(/ (- (g (+ x dx))
(g x))
dx)))
(define dx 0.0001)
(define (cube x) (* x x x))
((deriv cube) 5)
! 75.00014999664018
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
第1級手続き(first-class procedures)! 一般のプログラミング言語
! 通常,計算要素を扱う方法にいろいろな制限がある! 制限の殆どない要素は「第1級(first-class)の身分を持つ」と呼ばれる.
! 第1級要素の「権利と特権」! 変数として名前がつけられる! 手続きに引数として渡せる! 手続きの結果として返される! データ構造に組み込める
32
Lisp の手続き ... 完全な first-class status
効率のよい実装は困難だが,絶大な表現力
�#5
����������� Copyright (C) Nobuya WATANABE2012/05/14
まとめ! Lispの概要とSchemeの基本について説明
! 式! 名前と環境! 組合せの評価,合成手続き,手続き作用と置換えモデル! 条件式と述語! 内部定義とブロック構造! 高階手続き! lambda,局所変数
! 次回! Lispにおけるデータ構造
! 記号処理(リスト処理)
33