我正在使用 F# 对掷骰子进行一些蒙特卡罗模拟,我使用整数来表示单次掷骰子,并使用整数列表来表示掷骰子列表。我希望能够将掷骰子而不是整数建模为一种类型。我只使用 6 面骰子,我想要一种类型,它具有别名/同义词类型的一些特征以及可区分联合或枚举的一些属性。

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

  • 我希望类型表现得像一个整数,这样我就可以在列表上进行最大/最小/总和/折叠。
  • 我希望能够将类型分配为整数值。
  • 我希望类型被限制为 1-6,这样就可以没有零的骰子和七的骰子。

  • 我尝试了上面列出的类型的组合,但似乎都有一些缺点(这可能是我的用法和理解,而不是类型本身)。

    这只是我为了好玩(不是利润)而做的事情的一个小例子,但我想看到一个答案,因为我可以想象在更严肃的数据建模中使用它。

    最佳答案

    似乎带有一些静态方法的 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 = falseD6.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

    关于f# - 在 F# 中建模掷骰子,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26737560/

    10-09 15:53