How to get around the ambiguity problem when a monomorphic constraint is rotated * by *?

So, while studying Haskell, I came across a terrible monomorphic restriction, soon enough, with the following (in ghci):

Prelude> let f = print.show Prelude> f 5 <interactive>:3:3: No instance for (Num ()) arising from the literal `5' Possible fix: add an instance declaration for (Num ()) In the first argument of `f', namely `5' In the expression: f 5 In an equation for `it': it = f 5 

So there is a ton of material about this, for example. here , and it's not that hard to get around. I can either add an explicit type signature for f, or I can disable the monomorphic constraint (with ": set -XNoMonomorphismRestriction" directly in ghci or in the .ghci file).

In some discussions about the monomorphic constraint, but it seems like a general tip is that this is normally disabled (and I was told that it is really disabled by default in newer versions of ghci).

So, I turned it off.

But then I ran into another problem:

 Prelude> :set -XNoMonomorphismRestriction Prelude> let (a,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int <interactive>:4:5: No instance for (System.Random.Random t0) arising from the ambiguity check for `g' The type variable `t0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance System.Random.Random Bool -- Defined in `System.Random' instance System.Random.Random Foreign.C.Types.CChar -- Defined in `System.Random' instance System.Random.Random Foreign.C.Types.CDouble -- Defined in `System.Random' ...plus 33 others When checking that `g' has the inferred type `System.Random.StdGen' Probable cause: the inferred type is ambiguous In the expression: let (a, g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int In an equation for `it': it = let (a, g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int 

This is actually simplified from the example code in the book "Real World Haskell", which does not work for me, and which you can find on this page: http://book.realworldhaskell.org/read/monads.html (this is the Monads chapter and function getRandom example, find "getRandom" on this page).

If I leave a monomorphic restriction on (or turn it on), then the code works. It also works (with a monomorphic constraint) if I change it to:

 Prelude> let (a,_) = System.Random.random (System.Random.mkStdGen 4) in a :: Int -106546976 

or if I set type 'a' before:

 Prelude> let (a::Int,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int -106546976 

but for this second workaround, I have to enable the extension 'scoped type variables' (using :: set -XScopedTypeVariables).

The problem is that in this case (problems with a monomorphic restriction), none of the workarounds seems to be generally applicable.

For example, perhaps I want to write a function that does something like this and works with arbitrary (or several) types, and, of course, in this case, I most likely want to stay in the new state of the generator (in 'g') .

The question is: how can I get around this problem as a whole and without directly indicating the exact type?

And it would also be great (as a newcomer to Haskell) to get more information about what is going on here and why these problems arise.

+2
source share
1 answer

When you define

 (a,g) = random (mkStdGen 4) 

then even if g itself always has type StdGen , the value of g depends on type a , since different types may differ depending on how much they use the random number generator.

Also, when you (presumably) use g later while a was originally polymorphic, there is no way to decide which type of a you want to use to calculate g .

So, taken alone, the above should be rejected as a polymorphic definition, since g is actually extremely ambiguous, and this ambiguity cannot be fixed on the site of use.

This is a common problem with let/where bindings, which bind several variables in a template and are probably the reason that the usual restriction of monomorphism treats them even more stringent than equations with one variable: with a template, you cannot even turn off MR by giving a signature polymorphic type.

When using _ instead, the GHC is presumably not worried about this ambiguity unless it affects the calculation of a . Perhaps he could find that g not used in the previous version and is handled similarly, but apparently does not.

As for workarounds without providing unnecessary explicit types, you can instead try replacing let/where one of the binding methods in Haskell, which is always monomorphic. The following works:

 case random (mkStdGen 4) of (a,g) -> a :: Int (\(a,g) -> a :: Int) (random (mkStdGen 4)) do (a,g) <- return $ random (mkStdGen 4) return (a :: Int) -- The result here gets wrapped in the Monad 
+3
source

All Articles