sierpinski :: Int -> Array (Int,Int) Char
sierpinski l = runSTArray $ do
arr <- newArray ((1,1),(63,32)) '_'
let drawLine x y len = forM_ [-len..len] $ \s -> writeArray arr (x+s,y-len) '1' --this part does not compile without FlexibleContexts \\* Non type-variable argument in the constraint: MArray a0 Char m (Use FlexibleContexts to permit this)
let rek n x y h | n == 0 = forM_ [0..h-1] (drawLine x y)
| otherwise = do
rek (n-1) x y (div h 2)
rek (n-1) (x + div h 2) (y - div h 2) (div h 2)
rek (n-1) (x - div h 2) (y - div h 2) (div h 2)
rek l 32 32 32
return arr
However changing array type from Char to Int is okay
sierpinski :: Int -> Array (Int,Int) Int
sierpinski l = runSTArray $ do
arr <- newArray ((1,1),(63,32)) 0
let drawLine x y len = forM_ [-len..len] $ \s -> writeArray arr (x+s,y-len) 1 --now ok
let rek n x y h | n == 0 = forM_ [0..h-1] (drawLine x y)
| otherwise = do
rek (n-1) x y (div h 2)
rek (n-1) (x + div h 2) (y - div h 2) (div h 2)
rek (n-1) (x - div h 2) (y - div h 2) (div h 2)
rek l 32 32 32
return arr
Can someone clarify why is this happening?
Thanks.
The reason is actually in the error message.
Non type-variable argument in the constraint:
MArray a0 Char m (Use FlexibleContexts to permit this)
When you use the literals '_'
and '1'
, Haskell infers that their type is Char
, then it runs up against the most typical problem that you get with constraints that are MultiParamTypeClasses
- constraints arguments aren't all type variables, yet that is what the Haskell report requires them to be. The signature Haskell wants to infer is something like
drawLine :: MArray a Char m => ...
This wasn't a problem before MultiParamTypeClasses
since all classes before had only one argument. Then, if that argument was not a type variable, all you had to do was check that that instance was derivable and if it was a type variable, you'd keep it as a constraint. With MultiParamTypeClasses
you often end up with in-between cases - some of the arguments are instantiated, some aren't. FlexibleContexts
lets you have this sort of mixture (and even some more). This is a safe extension (which I would love to see be part of Haskell 2020).
Int
? Why doesn't it give me the same error?It actually isn't directly about Int
. When Haskell sees the literals 0
and 1
, since numeric literals are overloaded, it only decides on a general type: Num a => a
. That means that the constraint Haskell infers is just
drawLine :: (Num n, MArray a n m) => ...
And this doesn't even need FlexibleInstances
since all constraints have arguments that are type variables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With