めもりんこ
ゼクルッシュさん*1が「メモ化」について面白い記事を書かれていました。
メモ〜化したりスマス。 Memoization and Tail Recursive Function - Bug Catharsis
ぼくならこう書く!というのを少し考えてみました。
最初はコメント欄に投稿しようかと思ったのですが、はてなのコメント欄は半角スペースが削除されちゃうので・・・。
open System open System.Collections.Generic let create<'Key, 'Value when 'Key : equality> () = Dictionary<'Key, 'Value> () let memoize f = let dic = create () fun x -> if not (dic.ContainsKey(x)) then dic.Add(x, f x) dic.[x] let curry2 f x y = f (x, y) let curry3 f x y z = f (x, y, z) let uncurry2 f (x, y) = f x y let uncurry3 f (x, y, z) = f x y z let memo curry uncurry f = let m = memoize (uncurry f) in curry m let memoize0 f = let m = lazy f () in (fun () -> m.Value) //2011年1月5日 修正 let memoize2 f = memo curry2 uncurry2 f let memoize3 f = memo curry3 uncurry3 f
人間それぞれ個性を持っていますから、人と人とを比較することはできませんし、そんなことに意味はありません。
でもF#のタプルは比較することができます!
(1, 2) = (1, 2) は true です。
というわけで Dictionary
そのトリックを使ったのが上記のコード。
memoize0はちょっと卑怯ですが、卑怯なくらいが丁度いい。(え?)←改良しました!
一応実行例も載せておきます。(対話環境):
> let f0 () = printfn "I'm f0 !" ; 0 ;;
val f0 : unit -> int> let f0' = memoize0 f0 ;;
val f0' : (unit -> int)> f0' (), f0' ();;
I'm f0 !
val it : int * int = (0, 0)
> let f1 x = printfn "I'm f1 !" ; x + 1 ;;
val f1 : int -> int> let f1' = memoize f1 ;;
val f1' : (int -> int)> f1' 9, f1' 9 ;;
I'm f1 !
val it : int * int = (10, 10)
> let f2 x y = printfn "I'm f2 !" ; x + y ;;
val f2 : int -> int -> int> let f2' = memoize2 f2 ;;
val f2' : (int -> int -> int)> f2' 2 8, f2' 2 8 ;;
I'm f2 !
val it : int * int = (10, 10)
> let f3 x y z = printfn "I'm f3 !" ; x + y + z ;;
val f3 : int -> int -> int -> int> let f3' = memoize3 f3 ;;
val f3' : (int -> int -> int -> int)> f3' 2 3 5, f3' 2 3 5 ;;
I'm f3 !
val it : int * int = (10, 10)> f3' 3 2 5 ;; //順番を変えると・・・
I'm f3 !
val it : int = 10
第53回勉強会
今日はCLR/Hの勉強会。
僕は用事があって懇親会しか参加できませんでした。
↓僕が参加する前に撮られた写真
(via 仮装かセミナー in 札幌 ~仮想化のつもりが~ – 高添はここにいます) 続きを読む
ScalaとHaskellがF#に救いの手を
F# Advent Calendar jp 2010 第1回目!
F#の弱点(?)のひとつに、C#でいう try-catch-finally の仕組みが無いという点が挙げられます。
F#ではどのようにするかというと、try-with と try-finally をネストすることによって解決します。
「この、ねすとねすとした感じ、どうにかなりませんか!」
この問題を解決するヒントが、ScalaとHaskellにあります。
ご存知(?)Either型!
属性の定義
F#での属性の定義に関する情報って何か少なくない・・・?
気のせいでしょうか。
まあC#とほとんど変わらないのですが、一応例を残しておこうと思います。
open System // // サンプル属性 // [<AttributeUsage(AttributeTargets.All)>] // こんな属性を付けよう type InformationAttribute(summary : string) = inherit System.Attribute() // こんなクラスを継承しよう member self.Summary = summary // 属性を取ってくる関数のサンプル let info (t : Type) = let f (t : Reflection.MemberInfo)= t.GetCustomAttributes(typeof<InformationAttribute>, false) |> Array.map (fun x -> x :?> InformationAttribute) |> Array.iter (fun x -> printfn "%s : %s" t.Name x.Summary) f t Array.iter f (t.GetMembers ()) printf "\n" // つくった属性を付けてみます [<Information("死んだじいちゃんが大事にしていたクラスです。")>] type AttrTestClass(x) = [<Information("貧弱なフィールドです") ; DefaultValue>] val mutable MyVal : int [<Information("繊細なメソッドです。")>] member self.MyMethod () = () [<Information("大胆なプロパティです。")>] member self.MyProperty = x [<Information("紳士的なenumです")>] type AttrTestEnum = XXX = 1 | YYY = 2 | ZZZ = 3
そして、例えば対話環境で以下のようにしゃべってみます。
> info typeofVS上では「///」によるXMLコメントのほうが便利だけども、対話環境で使うことを目的としたスクリプトにはこんな属性を付けてやってもいいかもしれません。;;
AttrTestClass : 死んだじいちゃんが大事にしていたクラスです。
MyMethod : 繊細なメソッドです。
MyProperty : 大胆なプロパティです。
MyVal : 貧弱なフィールドですval it : unit = ()
> info typeof;;
AttrTestEnum : 紳士的なenumですval it : unit = ()
いらないですね。そうですね。わかりました。すいません。
GeneralizableValueAttribute
特に意味はないのですが、頭痛を癒すためにVisual Studioを立ち上げました。ただのひとり遊びです。
type Person() = class end type Dog() = class end type Cat() = class end type MyCollection<'T>() = static let arr = new ResizeArray<'T>() // static がミソだよ! member self.Add = arr.Add override self.ToString() = typeof<'T>.Name + "\t× " + arr.Count.ToString() [<GeneralizableValue>] let collection<'T> = new MyCollection<'T>() [<EntryPoint>] let Main args = collection.Add <| Person() collection.Add <| Dog() collection.Add <| Cat() collection.Add <| Dog() collection.Add <| Cat() collection.Add <| Cat() printfn "%A" (collection<Person>) printfn "%A" (collection<Dog>) printfn "%A" (collection<Cat>) 0
Person × 1Main関数内だけ見るとなかなか不思議。
Dog × 2
Cat × 3
続行するには何かキーを押してください . . .
手当たり次第に詰め込んだのに、中の人がきちんと仕分けしてくれています。
ちなみに、GeneralizableValueAttribute を付けると関数に変換されるようです。
追記:コメント欄で いげ太さんにご指摘いただきましたが、この属性の有無は関係ないようです。
上の例だと以下のように展開されていました。
[GeneralizableValue] public static MyCollection<T> collection<T>() { return new MyCollection<T>(); }
Visual F# Express Edition の入手方法
2012/10/27 追記
Visual Studio Express 2012では無償でF#が使えます!
http://d.hatena.ne.jp/Nobuhisa/20121027/p1
おそらく、「F# Express」で検索する方が多いと思うので、その人たちを釣る誘導するためのタイトルです。
喜んでください!F#は無償で利用することができます!
ただし、「Express Edition」というものは用意されていません。
以下のものをインストールしてください。
- Visual Studio (2008|2010) Shell
- Microsoft F# CTP
Visual Studio Shell というIDEを用意し、その中にF#を組み込む形になります。
F# CTPだけでも利用可能ですが、この場合コマンドラインで実行することになります。
マシンパワー的にVS2010は厳しい!という方は、VS2008も選択可能です。
ダウンロードは以下から:
- http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=8e5aa7b6-8436-43f0-b778-00c3bca733d3
- http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=40646580-97fa-4698-b65f-620d4b4b1ed7
- http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b598327-9748-4052-884a-6ee737380dcd
なお、F# CTPはどんどん更新される可能性があるので、ダウンロードする前に最新版がないか確認されることをオススメします。(上記のリンクは現時点での最新版です)
SharpDevelop
SharpDevelop(http://sharpdevelop.net/OpenSource/SD/)でもF#がサポートされているようです。
MonoDevelop
MonoDevelop(http://functional-variations.net/monodevelop/)を利用すれば、Linux環境でもIDEを使ってF#を楽しめます!