I want to write a function that would take a String and a Char and randomly either prepend or append the Char to the String.
I am wrote this, but it doesn't work because of some the type signature is the last line:
join :: RandomGen g => [Char] -> Char -> g -> ([Char], g)
join letters letter g = if inverse
then (letter:letters, newG)
else (letters [letter], newG)
where (inverse, newG) = random g :: (Bool, RandomGen)
error i get:
• Expecting one more argument to ‘RandomGen’
Expected a type, but ‘RandomGen’ has kind ‘* -> Constraint’
• In an expression type signature: (Bool, RandomGen)
In the expression: random g :: (Bool, RandomGen)
In a pattern binding:
(inverse, newG) = random g :: (Bool, RandomGen)
So how do I properly generate a boolean value and return the new generator from the function?
CodePudding user response:
The type of random g
is not since (Bool, RandomGen)
RandomGen
is a typeclass , not a type.
We can specify the type of inverse
through a type application and thus implement this as:
{-# LANGUAGE TypeApplication #-}
join :: RandomGen g => [Char] -> Char -> g -> ([Char], g)
join letters letter g
| inverse = (letter:letters, newG)
| otherwise = (letters [letter], newG)
where (inverse, newG) = random @Bool g
That being said, since inverse
is used by a guard (or if … then … else …
) the compiler knows that inverse
is a Bool
, and thus it can work out the types for inverse
and newG
. It is thus sufficient to define join
as:
join :: RandomGen g => [Char] -> Char -> g -> ([Char], g)
join letters letter g
| inverse = (letter:letters, newG)
| otherwise = (letters [letter], newG)
where (inverse, newG) = random g
It might also be better to use another name than join
, since join :: Monad m => m (m a) -> m a
is a function often used when working with monads.