• ch.5 型無しラムダ計算
    • 5-2 ラムダ計算でのプログラミング
  •  #  chapter 5. 型無しラムダ計算
    •  #  section 5-2. ラムダ計算でのプログラミング
      演習 5.2.1 論理演算の or 関数、not 関数を実装せよ。

      tru=λt.λf. t
      fls=λt.λf. f
      and=λb.λc. b c fls

      <or演算>
      A or B は、
      • A が tru なら tru を返す
      • A が fls なら B を返す
      このことから、 or = λb.λc. b tru c

      <not演算>
      not 演算は tru, fls を入れ替える。
      このことから、 not = λa. a fls tr

      演習 5.2.2 後者関数を定義する別の方法をみつけよ。

      c0=λs.λz. z
      c1=λs.λz. s z
      succ=λn.λs.λz. s (n s z)
      succ'=λn.λs.λz. n s (s z)

      演習 5.2.3 plus を用いずに Church 数の乗算を定義せよ。

      plus=λm.λn.λs.λz. m s (n s z)
      times=λm.λn. m (plus n) c0
      times'=λm.λn.λs.λz. m (n s) z

      演習 5.2.4 ある数を他の数で累乗する項を定義せよ。

      pow = λm.λn. n (times m) c1
      plus/timesの定義と同じような感じで
      (補足:ゼミにて、 λm.λn. n m という別解がある by asai 先生)

      演習 5.2.5 prd と使って減算の関数を定義せよ。

      sub = λm.λn. n pred m
      m から n回 prdすればよい。

      演習 5.2.6 prd cn を計算するために、おおよそ何ステップの計算が必要か。

      prd cn=(λm. fst (m ss zz)) cn
      ->fst (cn ss zz)
      =fst ((λs.λz. s (s ... z)) ss zz)
      ->fst ((λz. ss (ss ... z)) zz)
      ->fst (ss (ss ... zz))
      =fst (ss (ss .. (pair c0 c0)))

      以降、ss (pair c_n1 c_n2) のような app の eval が n 回行われる。
      ss (pair c_n1 c_n2) を eval するためのステップ数を考える。
      pair の eval は既に終わっているものとする。
      ss (pair c_n1 c_n2)
      =(λp. pair (snd p) (plus c1 (snd p))) (pair c_n1 c_n2)
      ->pair (snd (pair c_n1 c_n2)) (plus c_n1 (snd (pair c_n1 c_n2)))
      ->(λs.λb. b (snd (pair c_n1 c_n2)) s) (plus c_n1 (snd (pair c_n1 c_n2)))
      ->λb. b (snd (pair c_n1 c_n2)) (plus c_n1 (snd (pair c_n1 c_n2)))
      ->λb. b ((pair c_n1 c_n2) fls) (plus c_n1 (snd (pair c_n1 c_n2)))
      ->λb. b (fls c_n1 c_n2) (plus c_n1 (snd (pair c_n1 c_n2)))
      ->λb. b ((λf. f) c_n2) (plus c_n1 (snd (pair c_n1 c_n2)))
      ->λb. b c_n2 (plus c_n1 (snd (pair c_n1 c_n2)))
      ->*λb. b c_n2 (c_n1+c_n2)
      (ここでかかるステップ数をn'とする)
      (c_n1+c_n2 は (plus ..) の eval が終わったもの)
      ★ plus の定義から、plus の評価には、
      2(引数うけとり) + 4(ボディ部 m s (n s z) の eval) = 6ステップ
      ★ (snd (pair c_n1 c_n2)) の評価には、
      2(pair部が引数うけとってλb. b c_n1 c_n2) +
       1(snd引数受け取り) + 3 (snd内部) = 6ステップ
      よって、 n' = 12

      ss (pair c_n1 c_n2) を正規形にするのに19回ステップ必要なので、合計 19n


      演習 5.2.7 等価性をブール値で返す equal を定義せよ

      equal c3 c3=λt.λf. t
      equal c3 c2=λt.λf. f

      iszero = λn. n (λa.λb. fls) tru
      equal = λm.λn. ((iszero (sub m n)) and (iszero (sub n m)))

      演習 5.2.8 リスト [x, y, z] は λc.λn. c (x (c y (c z n))) となる。nil の表現はどうなるか。要素 h とリスト t を受け取り、h を t の前につける関数 cons をかけ。isnil, head, tail も書いてみよ。

      nil=λc.λn. n
      cons=λh.λt.λc.λn. c h (t c n)
      isnil=λt. t (λa. fls) tru
      head=λt. t true n
      g=λh.λp. pair (snd p) (cons h (snd p))
      tail=λt. fst (t g (pair nil nil))

      演習 5.2.9 なぜ g の定義の中で、Churchブール値に関する Church ブール関数ではなく、プリミティブな if を使ったか。if でなく test を使った factorial を定義せよ。

      二つの異なる表現であるChurch ブール値と、プリミティブなブール値の使用を
      区別しなくてはならないから。
      (補足:上のは間違っている。この章では call-by-value を仮定しているため、test では発散してしまうから。上の理由はなんか勘違いをしている... むしろ上の理由だと、if 文を使っちゃいけないことになる。ので完全に勘違い)

      演習 5.2.10 プリミティブな自然数を対応する Church 数に変換する関数 churchnat を定義せよ。

      churchnat = fix g
      g = λcnat.λn. if (iszero 0) then (λa. c0) else (λa. scc (cnat (pred n)))

      演習 5.2.11 fix と 演習 5.2.8 のリストの表現を用いて Church数のリストの総和を計算する関数をかけ。

      sumall = fix g
      g = λsm.λt. if (isnil t) then (λa. c0) else (λa. (plus (head a) (sm (tail a))))

      演習 5.3.3 任意の項 t について、|FV(t)| <= size(t) を示せ。

      部分項に関する帰納法で示す。

      (i) t = x
      FV(t)={x}
      size(t)=1
      成立。

      (ii) t = λx.t1
      *1) t1 は t の部分項なので、帰納法の仮定より、|FV(t1)| <= size(t1)
      ここで、
      FV(t)=FV(t1) \ {x}
      size(t)=size(t1) + 1
      である。

      このことから、
      |FV(t)| <= |FV(t1)| かつ size(t1) <= size(t)
      *1 より、 |FV(t)| <= size(t)

      (iii) t = t1 t2
      *2) 帰納法の仮定より、 |FV(t1)| <= size(t1)、|FV(t2)| <= size(t2)
      ここで、
      FV(t)=FV(t1) ∪ FV(t2)
      size(t)=size(t1) + size(t2) + 1
      である。

      このことから、
      |FV(t)| <= |FV(t1)| + |FV(t2)|
      size(t1) + size(t2) = size(t) - 1
      *2 より、|FV(t1)| + |FV(t2)| <= size(t1) + size(t2)
      すなわち、 |FV(t)| <= size(t) - 1
      size(t) - 1 <= size(t) なので、|FV(t)| <= size(t) が示せた。

      演習 5.3.6 これらの規則を変更し、他の三種の評価戦略(完全β簡約・正規順序・遅延評価) を表現するようにせよ。

      演習以外の部分まだよんでいないのであとで解く。

      演習 5.3.7 演習3.5.16では行き詰まり状態の項が特別な変数 wrong へと評価されるものを定義した。この意味論を λNBへと拡張せよ。

      同様

      演習 5.3.8 「大ステップ」スタイルでλ項の評価規則を形式化するにはどうすればよいか。

      [大ステップの評価]
       B-Value
      v ↓ v

      t1 ↓ λx.t t2 ↓ vB-App
      t1 t2 ↓ [x -> v]t