14

類似: Haskell Random from Datatype

じゃんけんゲームのさまざまな武器を含むデータ型を作成しました。

data Weapon = Rock | Paper | Scissor

ここで、コンピューターがユーザーに対して使用するランダムな武器を生成したいと思います。最初に投稿した同様のリンクを見てみましたが、私には一般的すぎるようです。

他のタイプから乱数を生成できます。私が理解できるのは、データ型を Random クラスのインスタンスにする方法です。

4

5 に答える 5

16

のインスタンスWeaponを作成するかどうかに関係なく、 random を生成するには、数値をsにマップする方法が必要です。型を派生させると、s との間のマップがコンパイラによって定義されます。だからあなたは定義することができますWeaponRandomWeaponEnumInt

randomWeapon :: RandomGen g => g -> (Weapon, g)
randomWeapon g = case randomR (0,2) g of
                   (r, g') -> (toEnum r, g')

例えば。インスタンスを使用すると、次のインスタンスEnumも簡単に作成できます。WeaponRandom

instance Random Weapon where
    random g = case randomR (0,2) g of
                 (r, g') -> (toEnum r, g')
    randomR (a,b) g = case randomR (fromEnum a, fromEnum b) g of
                        (r, g') -> (toEnum r, g')

型にコンストラクターを追加または削除する可能性がある場合、Joachim Breitnerがすぐに提案しrandomRたように、型と同期して境界を維持するための最良の方法は、派生も行うことです。Bounded

data Weapon
    = Rock
    | Paper
    | Scissors
      deriving (Bounded, Enum)

instance Random Weapon where
    random g = case randomR (fromEnum (minBound :: Weapon), fromEnum (maxBound :: Weapon)) g of
                 (r, g') -> (toEnum r, g')
    randomR (a,b) g = case randomR (fromEnum a, fromEnum b) g of
                        (r, g') -> (toEnum r, g')
于 2012-08-04T20:32:17.440 に答える
8

Daniel Fischer のEnumアプローチは確かにこれを行うための優れた一般的な方法ですが、sから明示的なマッピングを使用する必要はありませInt。あなたもできる

instance Random Weapon where
  random g = case random g of
               (r,g') | r < 1/3    = (Rock    , g')
                      | r < 2/3    = (Paper   , g')
                      | otherwise  = (Scissors, g')

Doubleのインスタンスを使用しますRandom。これは派生Enumインスタンスよりも効率的ではありませんが、より柔軟です。たとえば、不等分布を簡単に定義できます。

  random g = case random g of
               (r,g') | r < 1/4    = (Rock    , g')
                      | r < 1/2    = (Paper   , g')
                      | otherwise  = (Scissors, g')

Scissors他の2つよりも可能性が高い場所。もちろん、不等分布が何らかの形でデータ型の標準的である場合にのみ、そのようなことを行う必要があります。この例では確かにそうではありません。

于 2012-08-05T10:31:00.757 に答える
8
{-# LANGUAGE FlexibleInstances, UndecidableInstances,
 ScopedTypeVariables, OverlappingInstances #-}

import System.Random

class (Bounded a, Enum a) => BoundedEnum a
instance (Bounded a, Enum a) => BoundedEnum a
instance BoundedEnum a => Random a where
   random gen = randomR (minBound :: a, maxBound :: a) gen
   randomR (f, t) gen =
     (toEnum r :: a, nextGen)
     where
       (rnd, nextGen) = next gen
       r = fromEnum f + (rnd `mod` length [f..t])

今、あなたは言うことができます:

r <- randomIO :: Anything

Anything はクラス Enum および Bounded のインスタンスでなければなりません。

于 2012-08-05T13:13:23.520 に答える
2

データのジェネレーターがある場合はoneof、Test.QuickCheck.Gen から使用できます。

于 2012-08-06T08:56:19.047 に答える