スポンサーサイト

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

F#入門初級編 第20回 Delegates と Events(8) DelegateEvent

前回まででEvent<,>型とEvent<>型を紹介してきましたが、最後にDelegateEvent型についてふれたいと思います。
 
まずシグネチャーは次のようになっています。
type DelegateEvent<'Delegate> =
 class
  new DelegateEvent : unit -> DelegateEvent<'Delegate>
  member this.Trigger : obj [] -> unit
  member this.Publish :  IDelegateEvent<'Delegate>
 end
 
Event<,>の場合はデリゲートの形がobj * arg -> unit (objはsender)でしたが、この場合はdelegateの型は、「任意のタプル型->unit」 になります。(タプルの要素数はひとつだけでもかまいません。)
trigerでobj[](obj型のarray)の其々の要素をタプルの要素に対応させたものに対して、登録してあるデリゲートがinvokeされます。
 
またPublishされるオブジェクトの型はIDelegateEvent型でこれは次のようなシグネチャーとなっています。
type IDelegateEvent<'Delegate> =
 interface
  abstract this.AddHandler : 'Delegate -> unit
  abstract this.RemoveHandler : 'Delegate -> unit
 end
 
 
例を挙げてみます。
 
type MyDel = delegate of string*int*int*int->unit
 
type PublisherExamp() =
    let _event1 = 
        new DelegateEvent<MyDel>()
    member this.SomethingHappen() =
        let now = System.DateTime.Now
        let tupple1 = now.ToString() //delegateがinvokeするタプルの第一成分を作成
        let tupple2 = now.Year
        let tupple3 = now.Month
        let tupple4 = now.Day
        //obj[]にしてトリガーを引く
        _event1.Trigger([|box tupple1;  box tupple2;box tupple3;box tupple4|]) 
        
    member this.Event1 = _event1.Publish
 
インスタンスを作成してハンドラーを登録します。
 
let pub = PublisherExamp()
pub.Event1.AddHandler(MyDel(fun s y m d -> printfn "string = %s year = %d month = %d day = %d" s y m d))
 
イベントをfireしてみます。
 
> pub.SomethingHappen();;
string = 2010/04/12 8:24:27 year = 2010 month = 4 day = 12
val it : unit = ()
スポンサーサイト

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

F#入門初級編 第19回 Delegates と Events(7) Event

さて、ここまではEvent<'Del,'Args>,IEvent<>,IEvent<,>,IObservable<>型について紹介してきましたが、今回はEvent<'T>型についてふれておきます。
 
Event<'T>のシグネチャーは次のようになります。
type Event<'T> =
 class
  new Event : unit -> Event<'T>
  member this.Trigger : 'T -> unit
  member this.Publish :  IEvent<'T>
 end
 
ということでEvent<'Del,'Args>との違いはPublishされるのが、IEvent<,>型ではなくIEvent<>型であることです。
 
一つ例を挙げてみます。
 
type WhatTimeDidItHappenEventArgs (dateTime : System.DateTime) =
    inherit System.EventArgs()
    member this.DateTime = dateTime
 
type PublisherExampWithDelg () =
    let _event1 = 
        new Event<WhatTimeDidItHappenEventArgs>()
    member this.SomethingHappen() =
        _event1.Trigger(new WhatTimeDidItHappenEventArgs( System.DateTime.Now ))
    member this.Event1 = _event1.Publish
 
let t = new PublisherExampWithDelg();;
let originalEvent = t.Event1
 
以前までの例にくらべるとdelegateの定義が不要になりTriggerの引数がタプルでなくなっています。
 
publishされるのはIEvent型の値ですから、Handlerクラスのインスタンスを登録するか、もしくはIEventはIObservableであることを利用してObservable.addを用いて関数を登録します。
 
まずはHandlerクラスのインスタンスを登録してみます。
> let myHandler =
    new Handler<WhatTimeDidItHappenEventArgs>(
           fun sender args -> printfn "%A event fired(by Handler)" args.DateTime
     ) ;;
 
val myHandler : Handler<WhatTimeDidItHappenEventArgs>
 
> originalEvent.AddHandler(myHandler);;
val it : unit = ()
 
つぎはObservable.addを利用して登録してみます。
> Observable.add (fun( args:WhatTimeDidItHappenEventArgs) -> 
                        printfn "%A triggered (by IObservable.add)" args.DateTime)  originalEvent;;
val it : unit = ()
 
(なお上はoriginalEvent.Add(fun( args:WhatTimeDidItHappenEventArgs) -> 
                        printfn "%A triggered (by IObservable.add)" args.DateTime)とも書くことができます。)
 
トリガーを引いてみます。
 
> t.SomethingHappen();;
2010/04/11 19:43:33 event fired(by Handler)
2010/04/11 19:43:33 triggered (by IObservable.add)
val it : unit = ()
 

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

F#入門初級編 第18回 Delegates と Events(6) IObservable

それでは前回に引き続きObservableモジュールのメソッドを紹介していきます。
 
下は何回も出てきている、サンプルコードです。
 
type WhatTimeDidItHappenEventArgs (dateTime : System.DateTime) =
    inherit System.EventArgs()
    member this.DateTime = dateTime
 
type DelegateForPublisherExampWithDelg = 
                    delegate of obj * WhatTimeDidItHappenEventArgs -> unit
 
type PublisherExampWithDelg () =
    let _event1 = 
        new Event< DelegateForPublisherExampWithDelg,WhatTimeDidItHappenEventArgs>()
    member this.SomethingHappen() =
        _event1.Trigger(this,new WhatTimeDidItHappenEventArgs( System.DateTime.Now ))
    [<CLIEvent>]
    member this.Event1 = _event1.Publish
 
let t = new PublisherExampWithDelg();;
let originalEvent = t.Event1
 
なお今回[<CLIEvent>]というアトリビュートがPublish部分についていますが、これはDLL化等して他の.NET言語からこのeventを利用する場合に必要となります。(今回は特に必要ありません。)
 
それでは順次Observableモジュールにあるメソッドを紹介していきます。
 
○Observable.map
これは、付加情報を変換します。
// Signature:
Observable.map : ('T -> 'U) -> IObservable<'T> -> IObservable<'U>
 
例では付加情報はWhatTimeDidItHappenEventArgs型になります。
よってこれから、時間だけを抜き出して新しいIObservable型を作ってみます。
 
let timeEvent = 
    originalEvent 
     |> Observable.map(fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                        whatTimeArgs.DateTime.TimeOfDay) 
時間を表示する関数を登録して使ってみます。
> timeEvent.Add(fun args -> printfn "triggered time = %A" args);;
val it : unit = ()
> t.SomethingHappen();;
triggered time = 06:44:38.9060260
val it : unit = ()
 
○Observable.choose
 
// Signature:
Observable.choose : ('T -> 'U option) -> IObservable<'T> -> IObservable<'U>
// Usage:
Observable.choose chooser source
 
これは、filterとmapをまとめたようなものです。
 
○Observable.merge
 
// Signature:
Observable.merge : IObservable<'T> -> IObservable<'T> -> IObservable<'T>
// Usage:
Observable.merge source1 source2
 
これは二つのeventを引数に取り、どちらか一方がfireする時、fireする新しいeventを返します。
 
○Observable.pairwise
 
// Signature:
Observable.pairwise : IObservable<'T> -> IObservable<'T * 'T>
 
// Usage:
Observable.pairwise source
 
これは付加情報の形を、(付加情報、付加情報)の形に直します。(どんな時に使うのでしょうか?)
 
○Observable.scan
 
// Signature:
Observable.scan : ('U -> 'T -> 'U) -> 'U -> IObservable<'T> -> IObservable<'U>
 
// Usage:
Observable.scan collector state source
 
これはEventにおけるfold関数のようなものです。
イベントが発火した時刻をリストで保持してみます。
 
let foldTimetEvent = 
    originalEvent 
     |> Observable.scan(fun s (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                         (whatTimeArgs.DateTime.TimeOfDay::s)) [] 
 
 
foldTimetEvent.Add(fun args -> printfn "triggered times = %A" args)  
 
使用してみます。
 
> t.SomethingHappen();;
triggered times = [07:59:10.5612280]
val it : unit = ()
> t.SomethingHappen();;
triggered times = [07:59:12.2574085; 07:59:10.5612280]
val it : unit = ()
> t.SomethingHappen();;
triggered times = [07:59:13.4018665; 07:59:12.2574085; 07:59:10.5612280]
val it : unit = ()
 
○Observable.split
 
// Signature:
Observable.split : ('T -> Choice<'U1,'U2>) -> IObservable<'T> -> IObservable<'U1> * IObservable<'U2>
 
// Usage:
Observable.split splitter source
 
二択型の関数を与えて、二つの窓口のタプルを返します。
 

let (splittEvent1, splittEvent2)= 
    originalEvent 
     |> Observable.split(fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                            if whatTimeArgs.DateTime.Second <30 then
                                Choice1Of2(whatTimeArgs.DateTime.ToString()) //string型
                            else
                                Choice2Of2(whatTimeArgs.DateTime.Second))    //int型
                          
 
splittEvent1 .Add(fun args -> printfn "triggered times = %s" args) 
splittEvent2 .Add(fun args -> printfn "triggered times = %d" args)    
 
> t.SomethingHappen();;
triggered times = 2010/04/11 18:48:29
val it : unit = ()
> t.SomethingHappen();;
triggered times = 31
val it : unit = ()
 
○Observable.subscribe
Eventがtriggerされる毎に、それに反応して関数を実行するオブジェクトを返します。
 
// Signature:
Observable.subscribe : ('T -> unit) -> IObservable<'T> -> IDisposable
 
// Usage:
Observable.subscribe callback source
 

> let MySubsriber = Observable.subscribe (fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) 
                                            -> printfn "triggered %A" whatTimeArgs.DateTime) 
                                       originalEvent    ;;
 
val MySubsriber : System.IDisposable
 
> t.SomethingHappen();;
triggered 2010/04/11 18:57:26
val it : unit = ()
 
Disposeすると、登録しておいた関数も取り除かれます。
 
> MySubsriber.Dispose();;
val it : unit = ()
> t.SomethingHappen();;
val it : unit = ()

F#入門初級編 第17回 Delegates と Events(5) IObservable

さて前回はEvent moduleの中のメソッドを紹介しました。今回はIObservableモジュール内のメソッドを紹介します。
 
一度例に戻ります。
 
type WhatTimeDidItHappenEventArgs (dateTime : System.DateTime) =
    inherit System.EventArgs()
    member this.DateTime = dateTime
 
type DelegateForPublisherExampWithDelg = 
                    delegate of obj * WhatTimeDidItHappenEventArgs -> unit
 
type PublisherExampWithDelg () =
    let _event1 = 
        new Event< DelegateForPublisherExampWithDelg,WhatTimeDidItHappenEventArgs>()
    member this.SomethingHappen() =
        _event1.Trigger(this,new WhatTimeDidItHappenEventArgs( System.DateTime.Now ))
    member this.Event1 = _event1.Publish
    
> let t = new PublisherExampWithDelg();;
val t : PublisherExampWithDelg
 > let originalEvent = t.Event1;;
val originalEvent :
  IEvent<DelegateForPublisherExampWithDelg,WhatTimeDidItHappenEventArgs> 
  
IEvent型というのは次のように定義されていました。
type IEvent<'Delegate,'Args when 'Delegate : delegate<'Args,unit> and 'Delegate :> System.Delegate> =
 interface
  inherit IObservable<'Args>
  inherit IDelegateEvent<'Delegate>
 end
 
ということで今回はObservable モジュールに準備されているIObservable<>型の値を引数にするメソッドを紹介します。
 
さて、イベントが点火されたとき、実行される手続きは前回はIDelegateEvent型であること(5行上を参照)を利用してAddHandlerを使って登録しましたが、今回はIObservable型であること(4行上を参照)を利用して関数を登録します。
 
Observableモジュールには次のようなaddメソッドがあります。
○Observable.add<'T>
 
// Signature:
Observable.add : ('T -> unit) -> IObservable<'T> -> unit
 
// Usage:
Observable.add callback source
 
よってこれを用いて手続きを登録してみます。
> Observable.add (fun (args : WhatTimeDidItHappenEventArgs) -> printfn "trigered at %A" (args.DateTime)) originalEvent;;
val it : unit = ()
 
トリガーを引いてみます。
> t.SomethingHappen();;
trigered at 2010/04/09 20:14:57
val it : unit = ()
 
こちらを使うとsenderオブジェクトは引数とできませんが、手軽に付加情報を引数とした関数を登録できます。
 
なお上は
originalEvent.Add (fun (args : WhatTimeDidItHappenEventArgs) -> printfn "trigered at %A" (args.DateTime)) と書くことができます。
 
 
それでは順番にObservableモジュールに準備されているメソッドを紹介していきたいと思います。
まずはObservable.filterとObservable.partitionです。前回Event.filterとEvent.partionを紹介しましたが、機能的にはほぼ同じなのですが、引数、返り値などの型が異なります。
 
Observable.filter : ('T -> bool) -> IObservable<'T> -> IObservable<'T>
Observable.partition : ('T -> bool) -> IObservable<'T> -> IObservable<'T> * IObservable<'T>
 
filterの方をつかってみます。
 
> let filteredEvent1 = 
    originalEvent 
     |> Observable.filter(fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                        whatTimeArgs.DateTime.TimeOfDay.Seconds < 10) ;;
 
val filteredEvent1 : System.IObservable<WhatTimeDidItHappenEventArgs>
 
> filteredEvent1.Add(fun (args : WhatTimeDidItHappenEventArgs) ->printfn "%A event fired" args.DateTime);;
val it : unit = ()
 
> t.SomethingHappen();;
2010/04/10 16:59:02 event fired
val it : unit = ()
> t.SomethingHappen();;
val it : unit = ()
> t.SomethingHappen();;
2010/04/10 16:59:04 event fired
val it : unit = ()
次はpartitionの方です。
 
次にpartitionの方を使ってみます。
 
> let (lessThan10Event,notLessThan10Event) = //2つの窓口
    originalEvent 
     |> Observable.partition(fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                        whatTimeArgs.DateTime.TimeOfDay.Seconds < 10) ;;
 
val notLessThan10Event : System.IObservable<WhatTimeDidItHappenEventArgs>
val lessThan10Event : System.IObservable<WhatTimeDidItHappenEventArgs>
 
> lessThan10Event.Add(fun  args ->printfn "秒は %A で10未満" args.DateTime);;
val it : unit = ()
> notLessThan10Event.Add(fun args -> printfn "秒は %A で10以上" args.DateTime);;
val it : unit = ()
 
Eventをfireしてみます。
 
> t.SomethingHappen();;
秒は 2010/04/10 17:04:59 で10以上
val it : unit = ()
> t.SomethingHappen();;
秒は 2010/04/10 17:05:01 で10未満
val it : unit = ()
 
さて、Observableモジュールのこれらの返り値はどれもIObservable<T'>型なので、|>を用いて繋げていくことができます。偶数秒でフィルターをかけて、その上で10秒未満と以上に分けた窓口を作ると次のようになります。
 
let (lessThan10AndEvenEvent,notLessThan10AndEvenEvent) = //2つの窓口
    originalEvent 
     |> Observable.filter(fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                        whatTimeArgs.DateTime.TimeOfDay.Seconds % 2 = 0) 
 
     |> Observable.partition(fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                        whatTimeArgs.DateTime.TimeOfDay.Seconds < 10) 
 
lessThan10AndEvenEvent.Add(fun  args ->printfn "秒は %A で10未満かつ偶数" args.DateTime)
notLessThan10AndEvenEvent.Add(fun args -> printfn "秒は %A で10以上かつ偶数" args.DateTime)
 
Eventをfireしてみます。
> t.SomethingHappen();;
秒は 2010/04/10 17:10:06 で10未満かつ偶数
val it : unit = ()
> t.SomethingHappen();;
val it : unit = ()
> t.SomethingHappen();;
秒は 2010/04/10 17:10:08 で10未満かつ偶数
val it : unit = ()
> t.SomethingHappen();;
秒は 2010/04/10 17:10:10 で10以上かつ偶数
val it : unit = ()
> t.SomethingHappen();;
val it : unit = ()

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

F#入門初級編 第16回 Delegates と Events(4)

今回は前回の続きでF#のControl.Event ModuleのIEvent型の値を引数にとる関数を紹介します。
 
まずはずっと使用しているPublisherExampWithDelgクラス関連のコードを再掲します。
 
type WhatTimeDidItHappenEventArgs (dateTime : System.DateTime) =
    inherit System.EventArgs()
    member this.DateTime = dateTime
 
type DelegateForPublisherExampWithDelg = 
                    delegate of obj * WhatTimeDidItHappenEventArgs -> unit
 
type PublisherExampWithDelg () =
    let _event1 = 
        new Event< DelegateForPublisherExampWithDelg,WhatTimeDidItHappenEventArgs>()
    member this.SomethingHappen() =
        _event1.Trigger(this,new WhatTimeDidItHappenEventArgs( System.DateTime.Now ))
    member this.Event1 = _event1.Publish
 
これで
> let t = new PublisherExampWithDelg();;
val t : PublisherExampWithDelg
 > let originalEvent = t.Event1;;
val originalEvent :
  IEvent<DelegateForPublisherExampWithDelg,WhatTimeDidItHappenEventArgs> 
  
としておいた上で例としてoriginalEventを引数とした例を順次みていきます。
 
○Event.partition
 
これは、窓口を付加情報が条件を満たす場合と、満たさない場合の二つに分けます。
 
// Signature:
Event.partition : ('T -> bool) -> IEvent<'Del,'T> -> IEvent<'T> * IEvent<'T> (requires delegate)
 
// Usage:
Event.partition predicate sourceEvent
 
//Parameters
predicate
Type: 'T -> bool
The function to determine which output event to trigger.
 
sourceEvent
Type: IEvent<'Del,'T>
The input event.
 
関数の返り値は IEvent<'T> * IEvent<'T>となっていますから、満たす場合用の窓口と、満たさない場合用の窓口がタプルで返ります。(IEvent<>型ですから、Handler<>型をAddHandlerしていきます。)
時刻の秒が10未満用の時トリガーが引かれる窓口とそれ以外の場合にトリガーが引かれる窓口を作って使用してみます。
 
let (lessThan10Event,notLessThan10Event) = //2つの窓口
    originalEvent 
     |> Event.partition(fun (whatTimeArgs : WhatTimeDidItHappenEventArgs) ->
                        whatTimeArgs.DateTime.TimeOfDay.Seconds < 10) 
                        //Event.filterのEventはモジュール名
 
let myHandlerForLess10 =
    new Handler<WhatTimeDidItHappenEventArgs>(
           fun sender args -> printfn "秒は %A で10未満" args.DateTime
     )
 
let myHandlerForNotLess10 =
    new Handler<WhatTimeDidItHappenEventArgs>(
           fun sender args -> printfn "秒は %A で10以上" args.DateTime
     )
 
lessThan10Event.AddHandler(myHandlerForLess10)
notLessThan10Event.AddHandler(myHandlerForNotLess10)
 
eventを手動で発火してみます。
> t.SomethingHappen();;
秒は 2010/04/09 8:38:03 で10未満
val it : unit = ()
> t.SomethingHappen();;
秒は 2010/04/09 8:38:07 で10未満
val it : unit = ()
> t.SomethingHappen();;
秒は 2010/04/09 8:38:11 で10以上
val it : unit = ()
> t.SomethingHappen();;
秒は 2010/04/09 8:38:15 で10以上
val it : unit = ()

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

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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