学習の記録−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."