F# + WPF + Chart
F#の練習(特にオブジェクト指向らへん)。
さて、試してみよう試してみようと思いつつ絶賛放置プレイ中だった、
『Visifire』
という、チャートコンポーネントを今回使ってみた。
無性に使ってみたかったのである。なぜなら無償だから。
Silverlight or WPF のコンポーネンツです。WPFど素人の僕でも使えました。
式の評価にかかる時間をグラフ化するというそれだけのSOLUTION。
ダウンロードしてきて、圧縮ファイルを展開するとBinフォルダがこっちを見ているので、その中の『WPFVisifire.Charts.dll』という子をプロジェクトに追加してやります。WPFなので他に『PresentationCore』『PresentationFramework』『WindowsBase』なども追加してやる必要があります。
//#light "off" namespace StopwatchGUI open System open System.Windows open System.Windows.Controls /// とても計測するクラスです type CustomStopwatch() = class let watch = System.Diagnostics.Stopwatch() /// 評価したい式をLazyで凍結して渡します member self.Time (f:'T Lazy) = watch.Reset () watch.Start () ; f.Value |> ignore ; watch.Stop () watch.Elapsed end /// とても表示するクラスです type Viewer = class val private window : Window val private canvas : Canvas val private chart : Visifire.Charts.Chart val private dataSeries : Visifire.Charts.DataSeries new () = Viewer( 500.0, 350.0 ) new ( width, height ) as self = { canvas = Canvas( Name="main" ) window = Window( Title="StopwatchGUI", Width=width+50.0, Height=height+50.0 ) chart = Visifire.Charts.Chart( Width=width, Height=height ) dataSeries = Visifire.Charts.DataSeries() } then self.window.Content <- self.canvas self.chart.Series.Add self.dataSeries self.canvas.Children.Add self.chart |> ignore member self.AddItem caption value = let item = Visifire.Charts.DataPoint( YValue=value, AxisXLabel=caption ) self.dataSeries.DataPoints.Add item value member self.Show () = self.window.Show () end /// とても大会を主催するクラスです type ExpressionChampionship( evalCount:int ) = class let viewer = Viewer() let watch = CustomStopwatch() let times = evalCount new () = ExpressionChampionship( 1 ) member self.Entry (exp:'T Lazy) entryName = List.map (fun _ -> (watch.Time exp).TotalMilliseconds) [1..times] |> List.average |> viewer.AddItem entryName member self.MakePublic () = viewer.Show () end
戦いの準備は整いました。
試しに以下のように使ってみます。
(評価する式は以前の記事に書いたものをまた持ってきました)*1
open System open StopwatchGUI module Test = begin let rec sum_a = function | [] -> 0 | x :: xs -> x + (sum_a xs) let rec sum_b lst acc = match lst with | [] -> acc | x :: xs -> sum_b xs (x + acc) let sum_c = List.fold (+) 0 let sum_d lst = List.foldBack (+) lst 0 let main () = let ec = ExpressionChampionship( 5 ) let lst = [1..20000] let p = printfn "%A" p <| ec.Entry (lazy (sum_a lst)) "normal" p <| ec.Entry (lazy (sum_b lst 0)) "tail" p <| ec.Entry (lazy (sum_c lst)) "fold" p <| ec.Entry (lazy (sum_d lst)) "foldBack" ec.MakePublic () end #if COMPILED [<STAThread()>] do Test.main () let app = System.Windows.Application() app.Run () |> ignore #endif
すると、アニメーション付きのこのような棒グラフが表示されます。
引数なしの関数を呼び出す場合、
foo ()
のように unit を渡してますよオーラをビシビシ感じさせる書き方か、
foo()
のようにC#等でのメソッド呼び出しを連想させるような書き方にするかで個人的に迷ってます。(謎
と、まあ、こんな感じでした。
おしまい。
*1:F#CTPからVS2010βへの移行に合わせて、一部修正してます