Search code examples
haskellrandomtypeclass

Error in Haskell call to equation with expected type


I'm performing the following call to haskell method

rollD6 ::  (RandomGen g, Int a) => Int -> ([a], g)
rollD6 times =  roll Die6 times (mkStdGen 6)

rollD6InRange :: (RandomGen g, Int a) => Int -> Int -> Int -> ([a], g)
rollD6InRange times start end = rollR Die6 times start end (mkStdGen 6)

class Roll a where
  roll :: (RandomGen g) => a -> Int -> g -> ([Int], g)
  rollR :: (RandomGen g) => a -> Int -> Int -> Int -> g -> ([Int], g)

instance Roll Die where
  roll Die6 times = generateIntRandomsArray 1 6 times
  roll Die4 times = generateIntRandomsArray 1 4 times
  roll Die20 times = generateIntRandomsArray 1 20 times
  roll Die100 times = generateIntRandomsArray 1 100 times

  rollR Die6  times first last = generateIntRandomsArray first last times
  rollR Die4 times first last = generateIntRandomsArray first last times
  rollR Die20 times first last = generateIntRandomsArray first last times
  rollR Die100 times first last = generateIntRandomsArray first last times

generateIntRandomsArray :: (Eq a, Random a, Num a, RandomGen g) => a -> a -> a -> g -> ([a], g)
generateIntRandomsArray start end = generate
    where generate 0 generator = ([], generator)
          generate numberElements generator =
              let (value, newGenerator) = randomR (start,end) generator
                  (restOfList, finalGenerator) = generate (numberElements-1) newGenerator
              in  (value:restOfList, finalGenerator)

and I'm getting the following error

src/Merp/Die/Boundary/RollADie.hs:11:26: error:
    • Expected kind ‘* -> Constraint’, but ‘Int’ has kind ‘*’
    • In the type signature:
        rollD6 :: (RandomGen g, Int a) => Int -> ([a], g)
   |
11 | rollD6 ::  (RandomGen g, Int a) => Int -> ([a], g)
   |                          ^^^^^

src/Merp/Die/Boundary/RollADie.hs:14:32: error:
    • Expected kind ‘* -> Constraint’, but ‘Int’ has kind ‘*’
    • In the type signature:
        rollD6InRange :: (RandomGen g, Int a) =>
                         Int -> Int -> Int -> ([a], g)
    |
 14 | rollD6InRange :: (RandomGen g, Int a) => Int -> Int -> Int -> ([a], g)
    |                                ^^^^^

I've been playing with the parameters of the call, but I haven't been able to figure it out what is happening . Could you please give me a clue about what it's left ?


Solution

  • Int is not a typeclass, so:

    rollD6 :: (RandomGen g, Int a) => Int -> ([a], g)
    rollD6 times = roll Die6 times (mkStdGen 6)

    makes not much sense: you substitute a for Int, so:

    rollD6 :: RandomGen g => Int -> ([Int], g)
    rollD6 times = roll Die6 times (mkStdGen 6)

    The same holds for rollD6InRange.

    I would also advise to keep the type for the range and the number of elements, separate, so:

    generateIntRandomsArray :: (Random a, Integral b, RandomGen g) => a -> a -> b -> g -> ([a], g)
    generateIntRandomsArray start end = generate
      where
        generate 0 generator = ([], generator)
        generate numberElements generator =
          let (value, newGenerator) = randomR (start, end) generator
              (restOfList, finalGenerator) = generate (numberElements -1) newGenerator
           in (value : restOfList, finalGenerator)

    this allows us for example to generate from a sequence of Chars, Bools, Floats, or anything else that is an instance of Random [Hackage], for example:

    ghci> generateIntRandomsArray 'a' 'z' 10 (mkStdGen 0)
    ("nlrkwldbji",1695805043 1336516156)