学習の記録−5
モジュールの定義方法について
モジュール名とモジュールの計算結果として使用する型の名前が同じ場合を.NETは許さないので、モジュールの箇所に
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
を記述する。これで等から利用する場合、[モジュール名+Module]という名前になるので共存できる。モジュールのアクセス制御はtype, module, letの後にprivate, internal ,publicを記述することで可能。デフォルトはクラス内のlet束縛とかを除いてpublicらしい。
type public Jyanken = Gu | Ti | Pa [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module public Jyanken = type private Result = P1Win | TieGame | P2Win //unit -> int let private cpu () = match System.Random().Next(3) with | 0 -> Gu | 1 -> Ti | 2 -> Pa | _ -> failwith "unreachable" let private play p1 p2 = match p1, p2 with | Gu, Ti | Ti, Pa | Pa, Gu -> P1Win | Gu, Gu | Ti, Ti | Pa, Pa -> TieGame | Gu, Pa | Ti, Gu | Pa, Ti -> P2Win let public vsCpu you = let cpu = cpu () let res = match play you cpu with | P1Win -> "Win!" | TieGame -> "Tie" | P2Win -> "You lose" sprintf "[%s] You:%A VS Cpu %A" res you cpu
これを読ませた後、コンソールでじゃんけんしてみると
> Jyanken.vsCpu Ti;; val it : string = "[You lose] You:Ti VS Cpu Gu" > Jyanken.vsCpu Ti;; val it : string = "[You lose] You:Ti VS Cpu Gu" > Jyanken.vsCpu Ti;; val it : string = "[Win!] You:Ti VS Cpu Pa" > Jyanken.play Gu Ti;; Jyanken.play Gu Ti;; ^^^^^^^^^^^^ C:\Documents and Settings\Administrator\Local Settings\Temp\stdin(7,1): error FS1094: The value 'play' is not accessible from this code location
mutable と ref
変数それ自体が可変なのか、それとも参照先の中身が可変なのかが違う。あと演算子もちょい違う。
> let mutable x = 100;; val mutable x : int = 100 > x <- 110;; val it : unit = () > x;; val it : int = 110 > let y = ref 100;; val y : int ref = {contents = 100;} > y := 110;; val it : unit = () > !y;; val it : int = 110 > y := 10M;; y := 10M;; -----^^^ C:\Documents and Settings\Administrator\Local Settings\Temp\stdin(14,6): error FS0001: This expression was expected to have type int but here has type decimal
クロージャ
mutableだめ、refでやる。incrは参照用のインクリメント関数。
let counter x= let n = ref x (fun () -> incr n; !n)
> let c = counter 10;; val c : (unit -> int) > c ();; val it : int = 11 > c ();; val it : int = 12 > c ();; val it : int = 13
参照渡し
let swap (x : byref<'T>) (y : byref<'T>) = let z = x x <- y y <- z ;; > let mutable xx = 10;; val mutable xx : int = 10 > let mutable yy = 3;; val mutable yy : int = 3 > swap &xx &yy;; val it : unit = () > xx;; val it : int = 3 > yy;; val it : int = 10
リソースの束縛(use束縛)
通常はletで変数を束縛しているけど、.NETの外の世界にあるリソース(DBやファイル)はletの代わりにuseを使って束縛する。そうすると自動でリソースの破棄をしてくる。
using関数
第一引数にリソース突っ込んで、第二引数で処理。関数内でリソースの自動破棄してくれる
> using (File.OpenText(@"C:\hoge.txt")) (fun (reader : StreamReader) -> reader.ReadToEnd()) ;; val it : string = "Yes, We can! Financial Technology."