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