スポンサーサイト

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

F#によるデザインパターン入門 Iterator パターン(1) 外部イテレータ(1)

イテレータ(Iterator)は、何らかの容器に収納された値群から、それぞれの値を取り出してくる仕組みを外部に提供するものです。
 
F#では、容器としてよく使われるものに、List,array,Set等があります。
ここでは例としてarrayを対象にしてイテレータを定義してみたいと思います。(実際にはarrayにはイテレータは定義されているので、この操作は不必要です。)
 
まずは外部イテレータというものを定義してみます。これは容器(この場合array)と別のオブジェクトで、array内の値への、可動ポインタを提供するものです。とりあえずこれには二つのメソッドを実装することにします。
一つ目はMoveNextメソッドで、これはポインタを一つずらし、そこに要素があればtrueを返し、要素がなければfalseを返すというメソッドです。(最初にこれを呼び出すと最初の要素にポインタが移動することになります。)
もう一つはCurrentプロパティでこれはポインタ位置の値を返します。
それではint型のarrayに対して定義してみます。
 
> type myArrayIterator (in_array : array<int>) =
   let mutable index = -1
   member this.MoveNext() =
                if index < in_array.Length - 1 then
                    index <- index + 1
                    true
                else
                    false 
 
 
    member this.Current =
      in_array.[index];;
 
type myArrayIterator =
  class
    new : in_array:int array -> myArrayIterator
    member MoveNext : unit -> bool
    member Current : int
  end
 
使ってみます。
 
> let arr = [|5;4;3;2;1|];;
 
val arr : int [] = [|5; 4; 3; 2; 1|]
 
> let myAI00 = new myArrayIterator(arr);;
 
val myAI00 : myArrayIterator
 
> myAI00.MoveNext();;
val it : bool = true
> myAI00.Current;;
val it : int = 5
> myAI00.MoveNext();;
val it : bool = true
> myAI00.Current;;
val it : int = 4
 
whileループを用いてすべての要素を列挙してみます。
 
> let myAI01 = new myArrayIterator(arr)
 
while myAI01.MoveNext() do
    printfn "%d" myAI01.Current;;
5
4
3
2
1
 
val myAI01 : myArrayIterator
 
一般的に.NETでは、外部イテレータはIEnumeratorインターフェイスを実装したクラスとして定義します。(IEnumeratorインターフェイスを実装するにはCurrentというプロパティとMoveNext、Resetという2つのメソッドを定義する必要があります。CurrentとMoveNextは先ほどと同じ役割をするように実装し、Resetは「Resetを呼び出すことによりポインタが最初の状態になる」ように実装します。)
また外部イテレータを提供する容器側はIEnumrableインターフェイスを実装します。(これには、GetEnumeratorメソッドを実装し、このメソッド呼び出しで外部イテレータを生成して返すようにします。)
 
ではint型のarrayを保持するクラスで、IEnumerableインターフェイスを実装したものを例として作ってみます。
 
先に外部イテレータとして使用される、IEnumeratorインターフェイスを実装したクラスMyArrIterを定義します。
 
> type MyArrIter(iter_arr : array<int>) =
    let mutable index = -1
    interface IEnumerator with
        member this.MoveNext() =
                if index < iter_arr.Length - 1 then
                    index <- index + 1
                    true
                else
                false 
        member this.Reset() =
                index <- -1
         
        member this.Current =
                iter_arr.[index] :> obj;;
 
type MyArrIter =
  class
    interface IEnumerator
    new : iter_arr:int array -> MyArrIter
  end
 
次にMyArrIterクラスのインスタンスを外部イテレータとして発行する、IEnumerableインターフェイスを実装したクラスMyArrayを定義します。
 
> type MyArray (in_array : array<int>) =
    interface IEnumerable with
        member this.GetEnumerator() =
            (new MyArrIter(in_array)) :> IEnumerator;;
 
type MyArray =
  class
    interface IEnumerable
    new : in_array:int array -> MyArray
  end
 
では使用してみます。
まずMyArrayクラスのインスタンスを一つ作ります。
 
> let myArr00 = new MyArray([|5;4;3;2;1|]);;
 
val myArr00 : MyArray
 
次に外部イテレータを発行させて、これをmyArrIterという名前で束縛しておきます。
 
> let myArrIter00 = (myArr00 :> IEnumerable).GetEnumerator();;
 
val myArrIter00 : IEnumerator
 
外部イテレータを使って要素を調べてみます。
 
> myArrIter00.MoveNext();;
val it : bool = true
 
> myArrIter00.Current;;
val it : obj = 5
 
obj型になっていることに留意しておいてください。
 
> myArrIter00.MoveNext();;
val it : bool = true
> myArrIter00.Current;;
val it : obj = 4
> myArrIter00.MoveNext();;
val it : bool = true
> myArrIter00.Current;;
val it : obj = 3
> myArrIter00.MoveNext();;
val it : bool = true
> myArrIter00.Current;;
val it : obj = 2
> myArrIter00.MoveNext();;
val it : bool = true
> myArrIter00.Current;;
val it : obj = 1
> myArrIter00.MoveNext();;
val it : bool = false
 
 
外部イテレータを最初の状態に戻して、Whileですべての要素を表示してみます。
 
> myArrIter00.Reset();;
val it : unit = ()
 
> while myArrIter00.MoveNext() do
    printfn "%d" (myArrIter00.Current :?> int);;
5
4
3
2
1
val it : unit = ()
 
なお.NETではクラスがIEnumerableインターフェイスを実装していれば、for .. in ..を使用することができます。
 

 
> for i in (myArr00 :> IEnumerable) do
    printfn "%d" (i :?> int);;
5
4
3
2
1
val it : unit = ()
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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