用F#建模骰子

时间:2014-11-04 14:26:08

标签: f#

我正在使用F#对骰子卷进行一些蒙特卡罗模拟,我使用整数来表示一个骰子的卷和一个整数列表来表示骰子卷列表。我希望能够模拟骰子卷而不是整数作为一种类型。我只使用6面骰子,我希望这种类型具有Alias / Synonym类型的一些特性以及Discriminated Union或Enum的一些属性。

这些是我希望在我的类型上看到的

  1. 我希望该类型的行为类似于整数,因此我可以在列表上进行最大/最小/求和/折叠。
  2. 我希望能够将该类型指定为整数值。
  3. 我希望将类型约束为1-6,这样就不会有骰子卷零和七骰子卷。
  4. 我尝试过上面列出的类型组合,但似乎都有一些缺点(这可能是我的用法和理解,而不是类型本身)。

    这只是我为了娱乐而做的事情的一个微不足道的例子(不是利润),但我希望能够在更严肃的数据建模中看到答案。

2 个答案:

答案 0 :(得分:4)

作为其中一个选项,您可以创建自己的数字类型,如Tomas Petricek在本文中所述: http://tomasp.net/blog/fsharp-custom-numeric.aspx/index.html

答案 1 :(得分:3)

似乎是一个带有一些静态方法的Discriminated Union可以处理你想要的一切

open System

type D6 = 
    | One | Two | Three | Four | Five | Six

    member self.Value =
        match self with
        | One  -> 1      | Two  -> 2      | Three -> 3
        | Four -> 4      | Five -> 5      | Six   -> 6

    override self.ToString() =
        match self with
        | One  -> "One"  | Two  -> "Two"  | Three -> "Three"
        | Four -> "Four" | Five -> "Five" | Six   -> "Six"

    static member Create (num:int) =
        match num with
        | 1    -> One    | 2    -> Two    | 3     -> Three   
        | 4    -> Four   | 5    -> Five   | 6     -> Six     
        | _    -> failwithf "Could not create D6, %d is not in range 1-6" num

    static member inline Roll() = Random().Next(1,7) |> D6.Create

调用D6.Roll()将生成单个随机滚动

> D6.Roll();; val it : D6 = Four

> D6.Roll();; val it : D6 = Six

> D6.Roll();; val it : D6 = Two

> D6.Roll();; val it : D6 = Five

您可以创建静态成员和操作符,以便轻松组合D6

    static member inline Add      (a:D6) (b:D6) = a.Value + b.Value
    static member inline (+)      (a    , b   ) = D6.Add a b
    static member inline Subtract (a:D6) (b:D6) = a.Value - b.Value
    static member inline (-)      (a    , b   ) = D6.Subtract a b

静态成员,可以轻松地从输入列表

创建它们
    static member FromList (numls: int list ) =
        numls |> List.map D6.Create

比较使用此类型的框

D6.One > D6.Two;; val it : bool = false

D6.One < D6.Two;; val it : bool = true

无限序列可以轻松生成随机输入

let rollGen =
    let rnd = Random()
    let rec gen() = seq {   yield rnd.Next(1,7) 
                            yield! gen()        }
    gen()

> rollGen;; val rollGen : seq<int>

可以映射以创建无限随机序列D6

let d6Gen = rollGen |> Seq.map D6.Create 

> d6Gen;; val d6Gen : seq<D6>

如果你想拉出一个静态的输入值列表,你可以从随机无限序列中重复使用,你需要使用像

这样的函数
let rollList num = rollGen |> Seq.take num |> List.ofSeq

let d6List   num = d6Gen   |> Seq.take num |> List.ofSeq ;;

let _20rolls = rollList 20 ;;

> val _20rolls : int list = [3; 4; 2; 3; 5; 6; 4; 6; 6; 6; 5; 3; 4; 3; 2; 1; 2; 5; 3; 6]*)

let _30d6 = d6List 30 ;;

> val _30d6 : D6 list = [Two; Six; One; Three; Two; Three; One; One; Six; Six; Four; Four; Three; Four; One; Five; Three; Four; Four; Four; Three; Two; Six; Four; One; Three; One; Five; Two; Two]

Gist of just the code