スポンサーサイト

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

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

今回のお題は「Computation Expression(13) the state workflow(3)」です
 
前回でstate workflowの基本部品を紹介しましたが、今回必要となる部分だけを、もう一度ここで再掲します。
 
type StateFunc<'state,'a> = StateFunc of ('state -> 'a * 'state)
 
//StateFuncを関数としてsに作用させる
let Run (StateFunc f) s = f s
 
type StateBuilder () =
    //このBindの定義がState workflowのキモ
    member this.Bind(stfunc,rest) = 
        StateFunc(fun old_s ->
                let v,new_s = Run stfunc old_s
                Run (rest v) new_s
             )                         
 
//stateをそのまま値とstateにセットする(StateFunc型のオブジェクトを返す)
let GetState = StateFunc ( fun s -> (s,s))
 
//stateを引数にして、(何でも->((),state)というStateFunc型のオブジェクトを返す
let SetState s = StateFunc (fun _ -> ((),s))
 
let state = StateBuilder()
 
まとめとして、「let!やdo!の部分では、右辺の表す作用で、前のstate(状態)から、次の値と状態を作成して、その値と状態を前提として、次の行の処理に移る」と考えればよいと述べました。
 
それでは、stateをstring listとして、バックグラウンドで何らかの動作の記録をとることにします。
たとえば
 
push button A
push button C
push button B
 
とう動作に対して、履歴が["pushB";"pushC";"pushA"]というように残って行くようにしてみましょう。
 
pushButtonAを次のように定義します。
let pushButtonA =
    state {let! histroy = GetState 
           do! SetState ( "pushA" :: history) 
          }    
 
これをF#Interactiveに食わすと次のように表示されます。
 
val pushButtonA : StateFunc<string list,unit> = StateFunc <fun:bind@78>
StateFunc型であることに留意してください。
 
実行してみます。
 
> Run pushButtonA [];;
val it : unit * string list = (null, ["pushA"])
 
念のためにpushButtonAの定義をもう一度考えてみます、変換すると次のようになります。
 
let pushButtonA =
    state.Bind(GetState,fun history ->
                 SetState("pushA" :: history))
 
これを[]に適用すると、まずGetStateによって値が[],state(状態)も[]になります、
よって、rest vは,2行目以降はhisitoryの値は[]ということを表すので、この状態で、SetState("pushA" :: history)を状態である[]に作用させます。その結果((), ["pushA"])が返ります。
(()はnullと表示されます。)
 
pushButtonAはStateFunc型ですから、次のようにも使えます
let pushButtonATwice =
    state{  do! pushButtonA
            do! pushButtonA}
 
実行してみます。
    
> Run pushButtonATwice [] ;;
val it : unit * string list = (null, ["pushA"; "pushA"])
 
状態が裏で変化しているのをはっきりさせるために、次のように定義しなおして実行してみます。
 
let pushButtonATwice =
    state{  do! pushButtonA
            let! state1 = GetState
            printfn "%A" state1
            do! pushButtonA
            let! state2 = GetState
            printfn "%A" state2
            do! pushButtonA
            }
 
> Run pushButtonATwice [] ;;
["pushA"]
["pushA"; "pushA"]
val it : unit * string list = (null, ["pushA"; "pushA"; "pushA"])
 
さて、それではpushAの場合は1足されて、pushBの場合は100足されて、pushCの場合は10000足される電卓をつくります。
 
stateをint*string listに変更することを念頭においてコードを修正します。
 
let pushButton k kind =
    state {let! c_val,history = GetState 
           printfn "val = %d" c_val
           do! SetState ((c_val + k, "push" + kind :: history)) 
            }
 
let pushButtonA =
    pushButton 1 "A"
    
let pushButtonB =
    pushButton 10 "B"
 
let pushButtonC =
    pushButton 100 "C"
 
let pushButtonSample =
    state{  do! pushButtonA
            do! pushButtonC
            do! pushButtonB
            do! pushButtonA
            }
            
            
> Run pushButtonSample (0,[]) ;;
_val = 0
val = 1
val = 101
val = 111
val it : unit * (int * string list) =
  (null, (112, ["pushA"; "pushB"; "pushC"; "pushA"]))
  
それでは皆様、よいお年を。
スポンサーサイト

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

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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