Page 1
2012/05/21 1
言語処理系構成論(6)Lispプログラミング(2)
岡山大学大学院自然科学研究科渡邊誠也
2012/05/21
�#6
�����������
本日は金環日食! 岡山は部分日食
2
7:28頃ピーク
2012/05/21
�#6
�����������
はじめに! 言語処理系(解釈系,翻訳系)の動作,仕組みを
Lisp(Scheme)で記述することで理解を深める! 準備としてLisp(Scheme)について学ぶ
! Lisp(Scheme)の基本(その2)
3
! データによる抽象! データ抽象! 有理数の算術演算! 対(pair)
! 階層データ構造と閉包性! リスト構造のデータ! 閉包性! 並び(sequence)! リスト演算
! 記号データ! クォート! 例: 記号微分
2012/05/21
データによる抽象
4
2.1 Introduction to Data Abstraction
2012/05/21
�#6
�����������
データ抽象(Data abstraction)! 手続きの抽象化
! 手続きの実装の細部を隠蔽! 手続きが使われる方法を,手続きをより基本的な手続きを使って実装する方法の詳細から分離
! データ抽象! 手続きの抽象化と類似! 合成データオブジェクトの使い方を,それがより基本的データからどう作られたかの詳細から隔離する技法
! 基本的な考え方! 合成データオブジェクトを使うようにプログラムを構成し,「抽象データ」を操作できるようにする
! 「具体的な」データ表現はデータを使うプログラムから独立に定義! 選択子(selectors)と構成子(constructors)
5
2.1 Introduction to Data Abstraction
2012/05/21
�#6
�����������
例: 有理数の算術演算
6
2.1.1 Example: Arithmetic Operations for Rational Numbers
! 有理数を使った算術演算プログラムを考える! 仮定
! 分子と分母から有理数を作る方法! (make-rat n d) ... 分子が整数 n,分母が整数 d の有理数を返す
! 有理数から分子や分母をとりだす(選択する)方法! (numer x) ... 有理数 x の分子を返す! (denom x) ... 有理数 x の分母を返す
n1
d1+
n2
d2=
n1d2 + n2d1
d1d2
n1
d1� n2
d2=
n1d2 � n2d1
d1d2
n1
d1· n2
d2=
n1n2
d1d2
n1/d1
n2/d2=
n1d2
d1n2
n1
d1=
n2
d2n1d2 = n2d1 のときに限り
3つの手続きと上の式を使い,有理数の加減乗除,および等価性判定が可能
構成子(constructor)
選択子(selectors)
Page 2
2012/05/21
�#6
�����������
例: 有理数の算術演算(続き)
7
2.1.1 Example: Arithmetic Operations for Rational Numbers
n1
d1+
n2
d2=
n1d2 + n2d1
d1d2
n1
d1� n2
d2=
n1d2 � n2d1
d1d2
n1
d1· n2
d2=
n1n2
d1d2
n1
d1=
n2
d2
n1d2 = n2d1 のときに限り
有理数の加減乗除
n1/d1
n2/d2=
n1d2
d1n2
(define (add-rat x y) (make-rat (+ (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y))))
(define (sub-rat x y) (make-rat (- (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y))))
(define (mul-rat x y) (make-rat (* (numer x) (numer y)) (* (denom x) (denom y))))
(define (div-rat x y) (make-rat (* (numer x) (denom y)) (* (denom x) (numer y))))
2012/05/21
�#6
�����������
(define (div-rat x y) (make-rat (* (numer x) (denom y)) (* (denom x) (numer y))))
(define (mul-rat x y) (make-rat (* (numer x) (numer y)) (* (denom x) (denom y))))
(define (sub-rat x y) (make-rat (- (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y))))
例: 有理数の算術演算(続き)
8
2.1.1 Example: Arithmetic Operations for Rational Numbers
n1
d1+
n2
d2=
n1d2 + n2d1
d1d2
n1
d1� n2
d2=
n1d2 � n2d1
d1d2
n1
d1· n2
d2=
n1n2
d1d2
n1
d1=
n2
d2
n1d2 = n2d1 のときに限り
有理数の加減乗除
n1/d1
n2/d2=
n1d2
d1n2
(define (add-rat x y) (make-rat (+ (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y))))
有理数の等価性判
(define (equal-rat? x y) (= (* (numer x) (denom y)) (* (numer y) (denom x))))
選択子 numer, denom と構成子 make-rat を用いて定義した有理数に関する演算ができた 選択子と構成子の定義が必要
分子と分母を糊付けし...
2012/05/21
�#6
�����������
対(pair)
! 合成データオブジェクトの基本要素! 2つのパートで構成
! car部とcdr部! 基本手続きconsで構成
! 「consセル」とも呼ばれる
9
pair
car part cdr part
(define x (cons 1 2))
(car x)
==> 1
(cdr x)
==> 2
1 2
pairを組み合わせることで,複雑なデータ構造を作り出す
box-and-pointer notation
... pair は唯一必要な糊
2012/05/21
�#6
�����������
例: 有理数の表現! 有理数を2つの整数(分子と分母)の対 (pair) で表現
10
(define (make-rat n d) (cons n d))
(define (numer x) (car x))(define (denom x) (cdr s))
構成子(constructor)
選択子 (selectors)
(define (print-rat x) (newline) (display (numer x)) (display “/”) (display (denom x)))
表示用 (printer)
pair
car part cdr part
分子 分母
有理数
2012/05/21
�#6
�����������
例: 有理数システムの実行例
11
(define one-half (make-rat 1 2))
(print-rat one-half)
1/2
(define (one-third (make-rat 1 3))
(print-rat (add-rat one-half one-third))
5/6
(print-rat (mul-rat one-half one-third))
1/6
(print-rat (add-rat one-third one-third))
6/9
有理数 1/2 の生成有理数 1/2 の印字
有理数 1/3 の生成
※ 画面に印字されるもの(評価結果ではない)
1/2 + 1/3 の印字
1/2 × 1/3 の印字
1/3 + 1/3 の印字
簡約化なしmake-ratの変更のみで対応可(テキストを参照)
2012/05/21
�#6
�����������
抽象の壁! データ抽象の基盤となる考え
12
2.1.2 Abstraction Barriers
問題領域での有理数
分子と分母の有理数
対(pair)の有理数
対(pair)はどう実装してもよい
有理数を使うプログラム
add-rat, sub-rat, mul-rat, ...
make-rat, numer, denom
cons, car, cdr
有理数の演算: 構成子(make-rat)と選択子(numer, denom)を使って定義
データオブジェクトのそれぞれの型に対しその型のオブジェクトのすべての操作が表せるような基本の演算の組みを見出しこれらの演算のみでデータを操作すること有理数を使うプログラム: add-rat, sub-rat, ... のみを使って有理数を操作
構成子, 選択子は,対を使って実装
各レベルの手続き抽象の壁を定義異なるレベル間のインタフェース
Page 3
2012/05/21
階層データ構造と閉包性
13
2.2 Hierarchical Data and the Closure Property
2012/05/21
�#6
�����������
(car (car x)) ≡ (caar x)(car (cdr x)) ≡ (cadr x)(car (cdr (cdr x))) ≡ (caddr x)...
x:
y:
z:
リスト構造のデータ
14
1 2x:
3 4y:
z:
(define x (cons 1 2))
(define y (cons 3 4))
(define z (cons x y))
(car (car z))
==> 1
(car (cdr z))
==> 3
リスト構造のデータ(list structured data)
... 対で構成するデータオブジェクト
2.2.1 Representing Sequences
consは数値のみならず対(pair)さえも組み合わせることが可能
pair → あらゆる種類のデータ構造を構成するための万能構成部品(universal building block)を提供
2012/05/21
�#6
�����������
閉包性! consの閉包性(closure property of cons)
! 要素が対であるような対を作る能力 ! 表現用の道具としてのリスト構造の重要性の本質
! 閉包性(closure property)! データオブジェクトを組み合わせる演算は閉包性を満たす
! その演算を用いて何かを組み合わせた結果がまた同じ演算を用いて組み合わせられるとき
! 閉包 → それにより階層的構造を作ることが可能
15
部品からできた構造で,その部品がまた部品からできている
困ったことに,Lisp では,全く別の概念を表すclosure が...
2012/05/21
�#6
�����������
2.2.1 Representing Sequences
並び(sequence)
! データオブジェクトの順序づけられた集まり! 対を使って作ることの出来る有用な構造の1つ
16
(cons 1
(cons 2
(cons 3
(cons 4 nil))))リスト(list)
... 入れ子のconsで作られた対の並び
(list a1 a2 … an)
基本手続き list
1 2 3 4
(cons a1 (cons a2 (cons … (cons an�nil) … )))
等価
(1 2 3 4)
Lispシステムのリストの印字: 便宜的にかっこで囲まれた要素の並びを印字
要素の1つもない並び(空リスト(empty list))
nil ... ラテン語の「何もない」という意味の語nihilの短縮形
2012/05/21
�#6
�����������
部分リストの選択とリストへの要素の追加
17
(define one-through-four (list 1 2 3 4))
one-through-four
==> _________
(car one-through-four)
==> _
(cdr one-through-four)
==> _______
(car (cdr one-through-four))
==> _
(cons 10 one-through-four)
==> ____________
(cons 5 one-through-four)
==> ___________
1 2 3 4
one-through-four:
2012/05/21
�#6
�����������
部分リストの選択とリストへの要素の追加
17
(define one-through-four (list 1 2 3 4))
one-through-four
==> _________
(car one-through-four)
==> _
(cdr one-through-four)
==> _______
(car (cdr one-through-four))
==> _
(cons 10 one-through-four)
==> ____________
(cons 5 one-through-four)
==> ___________
1 2 3 4
one-through-four:
(1 2 3 4)
1
(2 3 4)
2 10
Page 4
2012/05/21
�#6
�����������
部分リストの選択とリストへの要素の追加
17
(define one-through-four (list 1 2 3 4))
one-through-four
==> _________
(car one-through-four)
==> _
(cdr one-through-four)
==> _______
(car (cdr one-through-four))
==> _
(cons 10 one-through-four)
==> ____________
(cons 5 one-through-four)
==> ___________
1 2 3 4
one-through-four:
(1 2 3 4)
1
(2 3 4)
2
(10 1 2 3 4)
10
5
2012/05/21
�#6
�����������
リスト演算(List operations)- リストの要素! 手続き: (list-ref list n)
! リストのn番目の要素を返す(n = 0, 1, 2, ...)! n = 0 なら,list の car部を返す! それ以外なら,list の cdr部 の (n - 1) 番目の要素を返す
18
(define (list-ref items n)
(if (= n 0)
(car items)
(list-ref (cdr items) (- n 1))))
(define squares (list 1 4 9 16 25))
(list-ref squares 3)
==> __
基本手続きとして組み込まれている
2012/05/21
�#6
�����������
リスト演算 - リストの長さ! リストの長さを返す手続き: (length list)
19
(define (length items)
(if (null? items)
0
(+ 1 (length (cdr items)))))
(define odds (list 1 3 5 7))
(length odds)
==> _
基本手続きとして組み込まれている
(null? obj) ...�obj が空リストか?
2012/05/21
�#6
�����������
リスト演算 - リストの結合! リストを結合し新しいリストを生成する手続き
21
(define (append list1 list2)
(if (null? list1)
list2
(cons (car list1)
(append (cdr list1) list2))))
(append squares odds)
==> (1 4 9 16 25 1 3 5 7)
(append odds squares)
==> (1 3 5 7 1 4 9 16 25)
odds: (1 3 5 7)squares: (1 4 9 16 25)
2012/05/21
�#6
�����������
リストの写像(Mapping over lists)! リストの各要素に対して手続きを作用させて結果をリストで返す
22
(define (map proc items)
(if (null? items)
nil
(cons (proc (car items))
(map proc (cdr items)))))
(map abs (list -10 2.5 -11.6 17))
==> (10 2.5 11.6 17)
(map (lambda (x) (* x x))
(list 1 2 3 4))
==> (1 4 9 16)
2012/05/21
�#6
�����������
階層構造(Hierarchical Structures)! リストの要素は,リストも可
23
(cons (list 1 2) (list 3 4))
==> ((1 2) 3 4)
3 4
1 2
(3 4)
(1 2)
((1 2) 3 4)
((1 2) 3 4)
(1 2)
1 2
3 4
2.2.2 Hierarchical Structures
Page 5
2012/05/21
�#6
�����������
階層構造(続き)- 葉の数をカウント
24 2012/05/21
�#6
�����������
階層構造(続き)- 葉の数をカウント
24
(define (count-leaves x)
(cond ((null? x) 0)
((not (pair? x)) 1)
(else (+ (count-leaves (car x))
(count-leaves (cdr x))))))
(define x (cons (list 1 2) (list 3 4))
(length x)
==> _(count-leaves x)
==> _(length (list x x))
==> _(count-leaves (list x x))
==> _
3 4
1 2
((1 2) 3 4)
2012/05/21
�#6
�����������
木の写像(Mapping over trees)! 葉が数値の木に対して,葉の数値を係数倍し同じ形の木を返す手続き
25
(define (scale-tree tree factor)
(cond ((null? tree) nil)
((not (pair? tree)) (* tree factor))
(else (cons (scale-tree (car tree) factor)
(scale-tree (cdr tree) factor)))))
2012/05/21
�#6
�����������
木の写像(Mapping over trees)
26
(define (scale-tree tree factor) (map (lambda (sub-tree) (if (pair? sub-tree) (scale-tree sub-tree factor) (* sub-tree factor))) tree))
【別の実装】
! 葉が数値の木に対して,葉の数値を係数倍し同じ形の木を返す手続き
3 4
1 2
(3 4)
(1 2)
((1 2) 3 4)
2012/05/21
記号データ
27
2.3 Symbolic Data
2012/05/21
�#6
�����������
クォート(Quotation)! 記号を操作するためには,ability of quote a data object が必要! リスト(a b)を作る際に(list a b)で作るわけにはいかない! クォート
! “say your name aloud’’ / “say ‘your name’ aloud’’
28
(define a 1)(define b 2)(list a b)==> _____(list ‘a ‘b)==> _____(list ‘a b)==> _____
(car ‘(a b c))
==> _
(cdr ‘(a b c))
==> _____
空リスト→ ‘()変数 nil が不要に
2.3.1 Quotation
Page 6
2012/05/21
�#6
�����������
memq
! 記号がリストに含まれているか?を調べる手続き! 含まれていないなら false を返す! 含まれていれば,最初に現れたその記号から始まる部分リストを返す
29
(define (memq item x)
(cond ((null? x) false)
((eq? item (car x)) x)
(else (memq item (cdr x)))))
(memq ‘apple ‘(pear banana prune))
==> _____
(memq ‘apple ‘(x (apple sauce) y apple pear))
==> ____________
(eq? obj1 obj2) ...�obj1 と obj2 が同じか?
false → jakld では #f
2012/05/21
�#6
�����������
例: 記号微分(Symbolic Differentiation)! 加算と乗算で構成される代数式の記号微分手続き
! 代数式と変数をとり,代数式のその変数に関する微分を返す
30
dc
dx= 0
dx
dx= 1
d(u + v)dx
=du
dx+
dv
dx
reduction rule
c: 定数または x と異なる変数
d(uv)dx
= u(dv
dx) + (
du
dx)v
rule 1
rule 2
rule 3
rule 4
再帰的な規則
2.3.2 Example: Symbolic Differentiation
2012/05/21
�#6
�����������
例: 記号微分(続き)! 以下の手続き群が既に定義されていることを想定
31
(variable? e) Is e a variable?(same-variable? v1 v2) Are v1 and v2 the same variable?(sum? e) Is e a sum?(addend e) Addend of the sum e.(augend e) Augend of the sum e.(make-sum a1 a2) Construct the sum of a1 and a2.(product? e) Is e a product?
(multiplier e) Multiplier of the product e.(multiplicand e) Multiplicand of the product e.(make-product m1 m2) Construct the product of m1 and m2.
2012/05/21
�#6
�����������
記号微分の手続き
32
(define (deriv exp var) (cond ((number? exp) 0) ((variable? exp) (if (same-variable? exp var) 1 0)) ((sum? exp) (make-sum (deriv (addend exp) var) (deriv (augend exp) var))) ((product? exp) (make-sum (make-product (multiplier exp) (deriv (multiplicand exp) var)) (make-product (deriv (multipler exp) var) (multiplicand exp)))) (else (error “unknown expression type -- DERIV” exp))))
基本述語: (number? obj) ...�obj�が数か?
2012/05/21
�#6
�����������
記号微分 - 代数式の表現! Lisp における式の表記法を用いる
33
ax + b(a * x + b)
(+ (* a x) b)
(define (variable? x) (symbol? x))(define (same-variable? v1 v2) (and (variable? v1) (variable? v2) (eq? v1 v2)))(define (make-sum a1 a2) (list ‘+ a1 a2))(define (make-product m1 m2) (list ‘* m1 m2))(define (sum? x) (and (pair? x) (eq? (car x) ‘+)))(define (addend s) (cadr s))(define (augend s) (caddr s))(define (product? x) (and (pair? x) (eq? (car x) ‘*)))(define (multiplier p) (cadr p))(define (multiplicand p) (caddr p))
2012/05/21
�#6
�����������
記号微分手続きの使用例! 使用例
34
(deriv ‘(+ x 3) ‘x)
==> (+ 1 0)
(deriv ‘(* x y) ‘x)
==> (+ (* x 0) (* 1 y))
(deriv ‘(* (* x y) (+ x 3)) ‘x)
==> (+ (* (* x y) (+ 1 0))
(* (+ (* x 0) (* 1 y))
(+ x 3)))
d(xy)dx
= x · 0 + 1 · y
= y
1
0
y
簡約化はされていないが正しい答え
x · 0 = 0
1 · y = y
0 + y = y
この程度の計算はして欲しい...
Page 7
2012/05/21
�#6
�����������
記号微分 - 式の簡約化
35
(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2)) (+ a1 a2))
(else (list ‘+ a1 a2))))
(define (=number? exp num)
(and (number? exp) (= exp num)))
(define (make-sum a1 a2)
(list ‘+ a1 a2))
! 手続き deriv は変更しないで実現! 構成子 make-sumとmake-product を変更
2012/05/21
�#6
�����������
記号微分 - 式の簡約化(続き)
36
(define (make-product m1 m2)
(cond ((or (=number? m1 0) (=number? m2 0)) 0)
((=number? m1 1) m2)
((=number? m2 1) m1)
((and (number? m1) (number? m2)) (* m1 m2))
(else (list ‘* m1 m2))))
(define (make-product m1 2)
(list ‘* m1 m2))
! 手続き deriv は変更しないで実現! 構成子 make-sumとmake-product を変更
2012/05/21
�#6
�����������
記号微分手続きの使用例(2)
! さらなる拡張として...! 扱える式を増やす (Exercise 2.56)
! 任意個(3個以上)の項の和と積に対応 (Exercise 2.57)
37
(deriv ‘(+ x 3) ‘x)
==> 1
(deriv ‘(* x y) ‘x)
==> y
(deriv ‘(* (* x y) (+ x 3)) ‘x)
==> (+ (* x y) (* y (+ x 3)))
手続き deriv の修正なしで,簡約化を実現!
d(un)dx
= nun�1(du
dx)
(* (* x y) (+ x 3))
(* x y (+ x 3))
rule 5
reduction rule
2012/05/21
�#6
�����������
まとめ! Lisp(Scheme)の基本(その2)
! データ,データ構造,リスト演算
38
! データによる抽象! データ抽象! 有理数の算術演算! 対(pair)
! 階層データ構造と閉包性! リスト構造のデータ! 閉包性! 並び(sequence)! リスト演算
! 記号データ! クォート! 例: 記号微分