0

I am doing an exercise in Haskell Programming from First Principles. It asks me to generate equal probabilities, and 1/3, 2/3 probabilities from each of:

data Fool =
  Fulse
  | Frue
  deriving (Eq, Show)

And my answer is

module Random where

-- import Test.Hspec
import Test.QuickCheck

data Fool =
  Fulse
  | Frue
  deriving (Eq, Show)


genFool :: Gen Fool
genFool = choose (Fulse, Frue)

genFool' :: Gen Fool
genFool' = do
  frequency [(2, return Fulse)
            ,(1, return Frue)]

but genFool is wrong. The error message is :

../chap14/random.hs:13:11: error:
    • No instance for (System.Random.Random Fool)
        arising from a use of ‘choose’
    • In the expression: choose (Fulse, Frue)
      In an equation for ‘genFool’: genFool = choose (Fulse, Frue)
   |
13 | genFool = choose (Fulse, Frue)
   |           ^^^^^^^^^^^^^^^^^^^^

Previously I have some code like this:

genBool :: Gen Bool
genBool = choose (False, True)

which works properly. I think there may be some predefined instance of System.Random.Random Fool to make the choose work.

What should I do to make the my version of genFool compile?

And btw, why is the return Fulse in the second genFool' of type Gen Fool?

cmal
  • 2,062
  • 1
  • 18
  • 35

1 Answers1

0

The Test.Quickcheck module's choose function has the following type signature:

choose :: Random a => (a, a) -> Gen a 

So, if you are planning to use choose function on your Fool type, it has to be made instance of Random typeclass as seen in the above type signature.

This is where Random typeclass is defined. It needs either a minimal implementation of either randomR and random.

Since your type Fool has only two values, it's isomorphic to Bool type. So, you can define a function mapping the values appropriately:

mapBool :: Bool -> Fool
mapBool False = Fulse
mapBool True = Frue

And then you can define a typeclass instance for your type:

instance Random Fool where
    random g = let (b :: Bool, g') = random g
               in (mapBool b, g')
    randomR _ g = (random g) -- Note that this doesn't work correctly. You need to pattern match and fix this.

The above code should make your module compile fine.

Sibi
  • 47,472
  • 16
  • 95
  • 163
  • No, a minimal definition needs both `randomR` and `random`. – melpomene Oct 23 '18 at 03:56
  • No extension is needed; your type annotation is redundant. – melpomene Oct 23 '18 at 03:57
  • @cmal I have given a sample implementation of `randomR`. Note that the first argument to `randomR` is a range. Since your type only contains two values, I'm skipping them entirely. You can modify it if you need a different behavior. – Sibi Oct 23 '18 at 04:38
  • Your implementation returns invalid results if you do e.g. `randomR (Frue, Frue)`. – melpomene Oct 23 '18 at 04:39
  • Thanks for the answer. If I want to implement randomR and random like the following, what should I change to make it compile? `instance Random Fool where randomR (Frue, Frue) g = (Frue,g) randomR (Fulse, x) g = do b <- getStdRandom (randomR (True, False)) return $ (if b then x else Fulse,g) random g = do b <- getStdRandom (randomR (True, False)) return $ if b then Frue else Fulse` Currently the error message is Couldn't match type ‘IO’ with ‘(,) Fool’ ... b <- getStdRandom (randomR (True, False)) – cmal Oct 23 '18 at 04:39
  • @melpomene Yeah, I know. The proper implemntation is : ``` randomR (Frue, Frue) g = (Frue, g) randomR (Fulse, Fulse) g = (Fulse, g) randomR _ g = random g ``` . But I think OP will be able to figure out from here. – Sibi Oct 23 '18 at 04:42
  • @cmal You shouldn't have a `do` block there (or call `getStdRandom`). – melpomene Oct 23 '18 at 04:48
  • Can you show me some code of `random g = ???`? Thanks a lot. @melpomene – cmal Oct 23 '18 at 04:54
  • @cmal It's here: https://stackoverflow.com/questions/52940687/no-instance-for-system-random-random-on-a-custom-typeclass-when-using-choose/52940820#comment92791019_52940820 – Sibi Oct 23 '18 at 14:34
  • @Sibi hi, it only defines `randomR`, but not `random g`. How to implement the `random g` ? Thanks! – cmal Oct 24 '18 at 02:17
  • @cmal `random g` is defined in my answer. – Sibi Oct 24 '18 at 04:35