6

Enumのインスタンスであり、のインスタンスでBoundedもあるすべての型を作成したいと思いますRandom。次のコードはこれを行い、動作するはずです (適切な拡張機能が有効になっている場合)。

import System.Random

instance (Enum r, Bounded r) => Random r where
   randomR (hi, lo) = inFst toEnum . randomR (fromEnum hi, fromEnum lo)
      where inFst f (x,y) = (f x, y)
   random = randomR (maxBound, minBound)

しかし、私はこれが悪いスタイルであることをinstance (Enum r, Bounded r) => Random r認識rEnumBoundedいます. これは事実上、すべてのタイプのインスタンスを定義していることを意味します。EnumBounded:(

別の方法としては、必要な動作を提供するスタンドアロン関数を作成し、インスタンスにしたい各型のボイラープレートを作成する必要がありますRandom

randomBoundedEnum :: (Enum r, Bounded r, RandomGen g) => g -> (r, g)
randomBoundedEnum = randomRBoundedEnum (minBound, maxBound)

randomBoundedEnumR :: (Enum r, Bounded r, RandomGen g) => (r, r) -> g -> (r, g)
randomBoundedEnumR (hi, lo) = inFst toEnum . randomR (fromEnum hi, fromEnum lo)
   where inFst f (x,y) = (f x, y)

data Side = Top | Right | Bottom | Left 
   deriving (Enum, Bounded)

-- Boilerplatey :( 
instance Random Side where
   randomR = randomBoundedEnumR
   random = randomBoundedEnum

data Hygiene = Spotless | Normal | Scruffy | Grubby | Flithy
   deriving (Enum, Bounded)

-- Boilerplatey, duplication :(
instance Random Hyigene where
   randomR = randomBoundedEnumR
   random = randomBoundedEnum

より良い代替手段はありますか?この問題をどのように管理すればよいですか? 私はこれを試みるべきではありませんか?ボイラープレートについて過度に心配していますか?

4

1 に答える 1

8

はい、少し関連した質問に答えたので、newtype ラッパーを使用できます。これは、コミュニティ全体を悩ませることなく、そのようなインスタンスを作成するための一般的で安全な方法です。

newtype RandomForBoundedEnum a = RfBE { unRfBE :: a}
instance (Enum a, Bounded a) => Random (RandomForBoundedEnum a) where
    ....

このように、このインスタンスを使用したいユーザーは、呼び出しをラップ (またはアンラップ) するだけです。

first unRfBE . random $ g :: (Side, StdGen)
于 2010-10-15T18:50:41.150 に答える