スポンサーサイト

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

F#雑記 falseとtrueを交互に返す方法

Gushwellさんのの記事や、BlUEPIXYさんの記事espresso3389さんの記事をみてやってみました。 
 
ちょっと違ったやりかたとして、無限数列と外部イテレーターを利用してやってみます。
まず
> let seqInf = Seq.initInfinite(fun index -> if (index % 2 = 0) then true else false);;
 
val seqInf : seq<bool>
 
としてture,falseが交互に現れる無限数列を定義します。
確かめてみます。
 
> seqInf;;
val it : seq<bool> = seq [true; false; true; false; ...]
 
次に外部イテレーターを取り出します。
 
> let iter = seqInf.GetEnumerator();;
val iter : System.Collections.Generic.IEnumerator<bool>
 
イテレータを一個進めて値を取り出す関数next()を定義します。
 
> let next ()  = 
        iter.MoveNext() |> ignore
        iter.Current;;
 
val next : unit -> bool
 
使ってみます。
> next() ;;
val it : bool = true
> next() ;;
val it : bool = false
> next() ;;
val it : bool = true
> next() ;;
val it : bool = false
 
ではクラス化します。コンストラクタには「indexと項の値を対応させる関数」を渡すことにします。
 
> type OneByOne1<'a> (initFunc : int -> 'a) =
    let seqInf = Seq.initInfinite(initFunc)
    let iter = seqInf.GetEnumerator()
    member this.next () = 
        iter.MoveNext() |> ignore
        iter.Current;;
 
type OneByOne1<'a> =
  class
    new : initFunc:(int -> 'a) -> CircleVals1<'a>
    member next : unit -> 'a
  end
 
 
使ってみます。
 
> let flipflop = new OneByOne1<bool>(fun index -> if (index % 2 = 0) then true else false);;
 
val flipflop : OneByOne1<bool>
 
> flipflop.next();;
val it : bool = true
> flipflop.next();;
val it : bool = false
> flipflop.next();;
val it : bool = true
> flipflop.next();;
val it : bool = false
 
次は朝昼晩で循環させてみます。
 
> let oneDay  = new OneByOne1<string>(fun index ->
                                          if index % 3 = 0 then "morning"
                                          elif index % 3 = 1 then "noon"
                                          else "night");;
 
val oneDay : OneByOne1<string>
 
> oneDay.next();;
val it : string = "morning"
> oneDay.next();;
val it : string = "noon"
> oneDay.next();;
val it : string = "night"
> oneDay.next();;
val it : string = "morning"
 
さて、無限数列といえばunfoldなので、これを使って別の表現をしてみたいと思います。
 
> type OneByOne2<'a,'b> (initFunc : 'b -> ('a*'b) option,initVal : 'b) =
    let seqInf = Seq.unfold(initFunc) initVal
    let iter = seqInf.GetEnumerator()
    member this.next () = 
        iter.MoveNext() |> ignore
        iter.Current;;
 
type OneByOne2<'a,'b> =
  class
    new : initFunc:('b -> ('a * 'b) option) * initVal:'b -> OneByOne2<'a,'b>
    member next : unit -> 'a
  end
 
使ってみます。
 
> let flipflop2 = new OneByOne2<bool,bool>((fun x -> Some(x,not x)),true);;
val flipflop2 : OneByOne2<bool,bool>
 
> flipflop2.next();;
val it : bool = true
> flipflop2.next();;
val it : bool = false
> flipflop2.next();;
val it : bool = true
> flipflop2.next();;
val it : bool = false
 
次は朝昼夜です。
 
> let day2 = new OneByOne2<string,int>
                ((fun x -> if x = 0 then Some("morning",1)
                           elif x = 1 then Some("noon",2)
                           else Some("night",0)),
                  0);;
 
val day2 : OneByOne2<string,int>
 
> day2.next();;
val it : string = "morning"
> day2.next();;
val it : string = "noon"
> day2.next();;
val it : string = "night"
> day2.next();;
val it : string = "morning"
 
ついでにフィボナッチ数列をひとつずつ取り出してみます。
 
> let fibo = new OneByOne2<int,int*int>
                ((fun (n1,n2) -> Some( n1 ,(n2 , n1 + n2))),
                (1,1));;
 
val fibo : OneByOne2<int,(int * int)>
 
> fibo.next();;
val it : int = 1
> fibo.next();;
val it : int = 1
> fibo.next();;
val it : int = 2
> fibo.next();;
val it : int = 3
> fibo.next();;
val it : int = 5
スポンサーサイト

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

コメントの投稿

非公開コメント

どうも

トラックバックどうもです、
ちょっと思ったのですが、
Seq.initInfinite って、結局 (int -> 'a) の関数を引数ということは、int ですよね。
オーバーフローして、2147483647→ -2147483648 というように無限に続いていくんでしょうか?
F#はデフォルトでは、オーバーフローチェックしないから多分そんな感じかと思うんですが

No title

コメントありがとうございます。
次のようなコードで調べてみました。(実行時間がとてもかかりました。)
let test = new OneByOne1<int64>(fun x -> int64(x))
let max = int64( System.Int32.MaxValue)
let rec loop (i : int64) =
if i > 2L * max + 10L then
()
else
let t = test.next()
if ((i >= max - 10L && i <= max + 10L))||((i >= 2L*max - 10L && i <= 2L*max + 10L))then
printfn "counter = %A : val = %A" i t
loop (i + 1L)
loop 0L

結果


counter = 2147483637L : val = 2147483637L
counter = 2147483638L : val = 2147483638L
counter = 2147483639L : val = 2147483639L
counter = 2147483640L : val = 2147483640L
counter = 2147483641L : val = 2147483641L
counter = 2147483642L : val = 2147483642L
counter = 2147483643L : val = 2147483643L
counter = 2147483644L : val = 2147483644L
counter = 2147483645L : val = 2147483645L
counter = 2147483646L : val = 2147483646L
counter = 2147483647L : val = 2147483647L

ハンドルされていない例外: System.InvalidOperationException: System.Int32 に基づ
く列挙型が System.Int32.MaxValue を超えました。
場所 Microsoft.FSharp.Collections.IEnumerator.upto@225.System-Collections-IEn
umerator-MoveNext()
以下略

ということで,Seq.initInfiniteのほうで無限数列を定義すると、2147483647で例外がraiseされます。
ちっとも無限数列ではないようです。
ちなみにソースコードを見てみたのですが、
let initInfinite f = mkSeq (fun () -> IEnumerator.upto None f)となっていて
IEnumerator.upto の定義内の
if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue))

というところで例外発生ではないかと思われます。



どうもすみません

>実行時間がとてもかかりました
すいません、すごく恐縮です。v-12(^_^;;;
なんかオーバーフローしないもんなんだろうと思っていましたが、
(自分でやってみる気にはなれませんでした)
オーバーフローするんですね。
mkSeq の方は見たんですが、
IEnumerator.upto の方は見てませんでした。

No title

すごく恐縮です->いえいえ別に、プログラム走らせて放置しておけばよいのですから、何でもないです。
マルチタスクに感謝です。(MS-DOSの時代を、ふと思い出してしまいました。)

No title

やはり、例外発生しましたか。


2値の繰り返しから、随分と発展しましたね。
unfoldは、思いつきませんでした。C#には無いんですよね。

No title

Gushwellさんコメントありがとうございます。しょっちゅうネタ元にさせて頂いております。
C#は2.0以降あまり勉強していないので、一回勉強しなおして追いつかなければと思っております。
Turbo C時代からアンダース・ヘルスバーグのファンなのです。

No title

>Turbo C時代からアンダース・ヘルスバーグのファンなのです。
僕は、Delphiからのファンです。
Turbo Cからとは随分と長いですね。
そのころは、Lattice-Cを使ってました。
プロフィール

T GYOUTEN

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

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

この人とブロともになる

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