SSブログ

Semantics with Applications を読んで denotational semantics について知る (2)

先に進む前に、前回みた while 文の意味の定義を振り返る。

文の semantic function から while 文のところだけを抜き出すと、

| While(condition, stm1) ->
    let f g = cond (b condition) (g $ (s stm1)) id in
    fix f

だった。ただし fix f は「f g = g になるような g」を返すものとする。この定義がそもそもどうやって出てくるのかを見ていきたい。まずは次のことがいえる。

「while b do S は if b then (S; while b do S) else skip と書き換えてもよい。」

これはどうやらその通りだ。というわけで、

| While(condition, stm1) ->
    s Cond(condition, Seq(stm1, While(condition, stm1)), Skip)

とする。条件文に対する semantic function の定義は、

| Cond(condition, stm1, stm2) -> cond (b condition) (s stm1) (s stm2)

だったから、

| While(condition, stm1) ->
    cond (b condition) (s Seq(stm1, While(condition, stm1))) (s Skip)

となる。順次実行の定義は、

| Seq(stm1, stm2) -> (s stm2) $ (s stm1) 

だったから、

| While(condition, stm1) ->
    cond (b condition) ((s While(condition, stm1)) $ (s stm1)) (s Skip)

となる。NOPの定義は、

| Skip -> id

だったから、さらに、

| While(condition, stm1) ->
    cond (b condition) ((s While(condition, stm1)) $ (s stm1)) id

となる。これはまだ、s While(condition, stm1) の内容を定義するために s While(condition, stm1) の全体を必要としているから、「統語範疇の意味はその構成要素だけから」決まるようにするという denotational semantics の目標に達していない。

ところでこの節は s の中の While に関する定義なのだから、必要とされる「s While(condition, stm1)」は「cond (b condition) (s While(condition, stm1)) $ (s stm1)) id」の戻り値でもある。

これを頭において、

cond (b condition) ((s While(condition, stm1)) $ (s stm1)) id : State.t -> State.t

の s While(condition, stm1) のところに穴をあけて関数化する、つまり、

fun g -> cond (b condition) (g $ (s stm1)) id : (State.t -> State.t) -> (State.t -> State.t)

としたときに、「s While(condition, stm1) : State.t -> State.t はこの関数の引数でもあるし戻り値でもある」ということになる。

ということはこの関数について「引数=戻り値となるような値」を見つけることができればどうだろうか。

fix をそのような手段とすれば While の定義は、

| While(condition, stm1) ->
    let f g = cond (b condition) (g $ (s stm1)) id in
    fix f

と書ける。この定義はもはや構成要素だけから決まるようになっている。これが while 文の定義がこんな形になっている理由だった。

なお、ある関数について「引数=戻り値となるような値」、つまり「f g = g となるような g」のことをその関数の fixed point と呼ぶ。

前回確認したのは関数の fixed point は複数ある場合があり、この定義だと fix が関数ではなく、したがって semantic function 全体も関数にならず、そうすると denotational semantics の目標が達成できないということだった。

だから fix は「fixed point が複数ある場合にもその中から適切な1つを選び取る」ように改修しなければならない。問題はその適切な1つをどのように定義するかだ。

Exercise 5.2 では while ~(x=0) do x := x-1 というプログラムには少なくとも次の2つの関数がその意味になってしまうということを見た。

let g2 = fun state ->
  if lookup "x" state >= 0
  then update "x" 0 state
  else undef ()
 
let g4 = fun state -> update "x" 0 state

「適切な1つ」は g2 のほうだ。この2つを見比べると、x が0以上の場合の結果は同じで、0未満だった場合の結果が違うことが見て取れる。0未満のとき g2 は停止せず、g4 は x を 0 にする。「0未満のとき停止せず」っていうのは「0未満の引数に対しては戻り値が定義されていない」ということだ。つまり関数の定義域に関していうと g2 のほうが g4 より小さい。これは g2 を選び取る基準に使えるのではないだろうか?

これ以降 fix を改修していくアイデアのあらすじは次のようなものになる。

- 関数を「順序付け」する方法を導入する
- fix は「一番小さい fixed point」を選び取るようにする

ここからまた様々な問題が立ちあがってくる。関数を順序付けするってどういうことか?その中で「一番小さいもの」って本当に決められるのか?


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。