スポンサーサイト

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

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

今回はuse,!useを紹介します。
 
これは共にUsingを使って次のように解釈されます。
 
use pat = expr in cexpr     b.Using(expr,(fun pat -> ≪cexpr≫))
 
use! pat = expr in cexpr    b.Bind(expr,(fun x -> b.Using(x,fun pat -> ≪cexpr≫)))
 
ここで、Usingの型は
 
member Using : 'a * ('a -> M<'a>) -> M<'a> when 'a :> IDisposable
 
というように定義されています。
 
すなわち、何かを使ってその後で後始末をする用途向きに用意されたメンバーです。
 
それでは、実験用に「破棄される側のもののクラス」を一つ定義しておきます。
 
type MyDisposeClass ()=
    member this.Display() =
        printfn "使用中"
    interface System.IDisposable with
        member this.Dispose() =
            printfn "破棄します"
            
解釈クラスを次のように定義します。
 
type UseBuilder01 () =
   member this.Bind(x,rest) =
      rest x     
   member this.Return (x) =
      x
   member this.Delay f =
      delay f
   member this.Using (x:'a when 'a :> System.IDisposable,rest)  =
      try
        rest x
      finally
        x.Dispose()
        
定義部分をF#Interactiveに食わしてみます。
 
type MyDisposeClass =
  class
    interface System.IDisposable
    new : unit -> MyDisposeClass
    member Display : unit -> unit
  end
val delay : (unit -> 'a) -> unit -> 'a
 
type UseBuilder01 =
  class
    new : unit -> UseBuilder01
    member Bind : x:'d * rest:('d -> 'e) -> 'e
    member Delay : f:(unit -> 'b) -> (unit -> 'b)
    member Return : x:'c -> 'c
    member
      Using : x:'a * rest:('a -> 'a0) -> 'a0 when 'a :> System.IDisposable
  end

 
それでは、次のように定義してみます。
 
let ub = new UseBuilder01()
 
let useSample =
    ub{
        use t = new MyDisposeClass()
        t.Display ()
        return 0
       }
 
実行すると、
> useSample();;
使用中
破棄します
val it : int = 0
 
となります。
 
その他オプションとして定義できるものにTryFinally,TryWithなどがあり,これは次のような型を持ちます。
○member TryFinally
{}の中の表現 try/finally
M<'a> * (unit -> unit) ->M<'a>
try/finally 
 
○member TryWith
{}の中の表現 try/with
M<'a> * (exn -> M<'a>) -> M<'a>
 
これらについては、後日実装例として紹介する予定です。
 
それでは最後にこれまで出てきたものなどを、一覧として再掲しておきます。
 
let! pat = exp in cexp        b.Bind(exp,(fun pat -> ≪cexp≫))
let pat = exp in cexp         b.Let(exp,(fun pat -> ≪cexp≫))
use pat = exp in cexp         b.Using(exp,(fun pat -> ≪cexp≫))
use! pat = cexp in cexp       b.Bind(exp,(fun x->b.Using(x,(fun pat-> ≪cexp≫))))
do! exp in cexp               b.Bind(exp,(fun () -> ≪cexp≫)) 
do exp in cexp                b.Let(exp,(fun () -> ≪cexp≫))
for pat in exp do cexp        b.For(exp,(fun pat -> ≪cexp≫))
while exp do cexp             b.While((fun ()-> exp),b.Delay(fun ()-> ≪cexp≫))
if exp then cexp1 else cexp2  if exp then ≪cexp1≫ else ≪cexp2≫ 
if exp then cexp              if exp then ≪cexp≫ else b.Zero() 
cexp1
cexp2                         b.Combine(≪cexp1≫, b.Delay(fun () -> ≪cexp2≫)) 
return exp                    b.Return(exp)
 
b.Letについては自己定義できないので
member this.Let(x,rest) = rest x
と解釈してください。

なお、私が調べたかぎりでは、computation expressionの最後の行以前のifについては、必ずb.Zero()が呼び出される模様です。(上とは矛盾しています。)ですから、ifを使用するのであれば、for,whileもZero()と同じ型を返す必要があります。(どれもCombineの引数のタプルの第一成分に渡される為)またcomputation expressionの最後の行がdoの場合もb.Zero()が呼び出される場合がある模様です。

スポンサーサイト

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

コメントの投稿

非公開コメント

No title

MyDisposeSample → MyDisposeClass
member this.Display → member this.Display ()
member this.Using<'a when 'a :> System.IDisposable> (x:'a,rest) →
member this.Using (x:'a when 'a :> System.IDisposable,rest)

後のは、バージョン違いによるもの?

b.Let
なんで、古いバージョンでの説明を、無効である新しいバージョンでもやり続けようとするのか
理解に苦しみます。

No title

訂正しました。
古いバージョンでの説明を、無効である新しいバージョンでもやり続けようとするのか
理解に苦しみます。->補足説明を忘れてました。
プロフィール

T GYOUTEN

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

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

この人とブロともになる

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