類似: Haskell Random from Datatype
じゃんけんゲームのさまざまな武器を含むデータ型を作成しました。
data Weapon = Rock | Paper | Scissor
ここで、コンピューターがユーザーに対して使用するランダムな武器を生成したいと思います。最初に投稿した同様のリンクを見てみましたが、私には一般的すぎるようです。
他のタイプから乱数を生成できます。私が理解できるのは、データ型を Random クラスのインスタンスにする方法です。
類似: Haskell Random from Datatype
じゃんけんゲームのさまざまな武器を含むデータ型を作成しました。
data Weapon = Rock | Paper | Scissor
ここで、コンピューターがユーザーに対して使用するランダムな武器を生成したいと思います。最初に投稿した同様のリンクを見てみましたが、私には一般的すぎるようです。
他のタイプから乱数を生成できます。私が理解できるのは、データ型を Random クラスのインスタンスにする方法です。
のインスタンスWeapon
を作成するかどうかに関係なく、 random を生成するには、数値をsにマップする方法が必要です。型を派生させると、s との間のマップがコンパイラによって定義されます。だからあなたは定義することができますWeapon
Random
Weapon
Enum
Int
randomWeapon :: RandomGen g => g -> (Weapon, g)
randomWeapon g = case randomR (0,2) g of
(r, g') -> (toEnum r, g')
例えば。インスタンスを使用すると、次のインスタンスEnum
も簡単に作成できます。Weapon
Random
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')
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つよりも可能性が高い場所。もちろん、不等分布が何らかの形でデータ型の標準的である場合にのみ、そのようなことを行う必要があります。この例では確かにそうではありません。
{-# 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 のインスタンスでなければなりません。
データのジェネレーターがある場合はoneof
、Test.QuickCheck.Gen から使用できます。