スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門中級編第12回(Computation Expression(12))

今回のお題は「Computation Expression(12) the state workflow(2)」です。
 
それでは宿題の解答から。。
(宿題)
次のように定義してRun Drill02 (3,[]) とすると返り値はなんでしょうか?
 
let Drill02 = 
    state{
        let! x = StateFunc (fun (sn,sl) -> (5*sn,(2*sn,(2*sn):: sl )))  //#1
        let  y = 100 * x               //#2
        let! z = StateFunc (fun (sn,sl) -> (7*sn,(3*sn,(3*sn):: sl )))  //#3
        return (x + y + z)             //#4
    }
 
まず留意するのは、状態がint型と、リストのタプルであることです。
例えば#1の部分ではStateFuncがStateFunc (fun (sn,sl) -> (5*sn,(2*sn,(2*sn):: sl )))なので、
タプルの第一成分を5倍したものが新しい値、「タプルの第一成分を2倍したものと、それをリストに付け加えたタプル」が新しい状態になります。
図で表すと
 
  (  x  ,    y   ,    z )   状態
#0 未定義 未定義   未定義      (3,[])
#1   15   未定義   未定義      (6,[6])   (fun (sn,sl) -> (5*sn,(2*sn,(2*sn):: sl )))
#2   15     1500   未定義    
#3   15     1500       42     (18,[18;6]) (fun (sn,sl) -> (7*sn,(3*sn,(3*sn):: sl )))
 
実行例は次のようになります。
 
> Run Drill02 (3,[]);;
stateの状態:(3, [])
stateの状態:(3, [])
stateの状態:(6, [6])
stateの状態:(6, [6])
stateの状態:(18, [18; 6])
val it : int * (int * int list) = (1557, (18, [18; 6]))
 
このように、状態にリストを絡ませて、状態の変化の度に、状態を追加することにより、状態のログをとることができます。
 
次の練習です。
次のように定義してRun Drill03 7 とすると返り値はなんでしょうか?
 
let Drill03 = 
    state{
        let! x = StateFunc (fun s -> (s,s))   //#1
        let  y = 100 * x                      //#2
        let! z = StateFunc (fun s -> (s,s))   //#3
        return (x + y + z)                    //$4
    }
 
答えは(714,7)です。
状態と値の変化を図示すると次のようになります。
  (  x  ,    y   ,    z )   状態
#0 未定義 未定義   未定義      7
#1    7   未定義   未定義      7        StateFunc (fun s -> (s,s)) 
#2    7      700   未定義      7
#3    7      700       7       7        StateFunc (fun s -> (s,s)) 
 
StateFunc (fun s -> (s,s))は、「状態を変えずに、値としてその状態を取り出す」という作用を持ちます。よって、バックグラウンドで動く状態を表に引きずり出す役割をするわけです。
このような形のStateFuncは良く使われるので、GetStateという名前で使われるのが慣例となっているようです。すなわち
let GetState = StateFunc ( fun s -> (s,s))
という形です。(もちろん、これを使う部分ではlet! の左辺の識別子の型は状態と同じ型になります。)
 
それでは次の例です。
次のように定義してRun Drill04 1 とすると返り値はなんでしょうか?
 
let Drill04 = 
    state{
        let! x = GetState                               //#1
        printfn "%d" x
        do!  (fun s ->StateFunc(fun _ -> ((),s)))  7    //#2
        let! y = GetState                               //#3
        printfn "%d" y
        return (x + y )                                 //#4
    }
 
ではとりあえず実行してみます。
> Run Drill04 1;;
1
7
val it : int * int = (8, 7)
 
まずは
do!  (fun s ->StateFunc(fun _ -> ((),s)))  7    //#2
に着目してください。do!はlet!の特別な場合(翻訳はlet!と同じBindが使われる)でした。
これは
do! StateFunc(fun _ -> ((),7))
と同じことになります。つまりどんな状態を受け取ろうとも、ここからの状態としては7として、以後考えなさいということです。(値の変化はありません。)
これは、ここまでの状態を一度御破算にして、新しい状態でここからリスタートするという作用をします。
これは新しいリセットする状態を引数として、SetStateという名前で次のように定義するのが慣例です。
 
//reset_sを引数にして、(何でも->((),reset_s)というStateFunc型のオブジェクトを返す
let SetState reset_s = StateFunc (fun _ -> ((),reset_s))
 
これを用いると#2は
do! SetState 7
と書けます。
 
ということで、#1でxは1となり、#2で状態は7となり、#3でyが7となるので、結果として値は1+7の8,状態は7となり(8,7)というタプルが返ります。
 
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。