[英]Using Char does not compile without FlexibleContexts
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 但是将数组类型从Char更改为Int是可以的
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. 当您使用文字
'_'
和'1'
,Haskell推断它们的类型是Char
,然后它会遇到MultiParamTypeClasses
约束所带来的最典型问题 - 约束参数不是所有类型变量,但是是Haskell报告要求它们。 The signature Haskell wants to infer is something like 签名Haskell 想要推断的是类似的东西
drawLine :: MArray a Char m => ...
This wasn't a problem before MultiParamTypeClasses
since all classes before had only one argument. 这在
MultiParamTypeClasses
之前不是问题,因为之前的所有类只有一个参数。 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. 使用
MultiParamTypeClasses
您经常会遇到中间情况 - 某些参数是实例化的,有些则不是。 FlexibleContexts
lets you have this sort of mixture (and even some more). FlexibleContexts
让你有这种混合(甚至更多)。 This is a safe extension (which I would love to see be part of Haskell 2020). 这是一个安全的扩展(我希望看到它成为Haskell 2020的一部分)。
Int
? Int
呢? Why doesn't it give me the same error? It actually isn't directly about Int
. 它实际上不是直接关于
Int
。 When Haskell sees the literals 0
and 1
, since numeric literals are overloaded, it only decides on a general type: Num a => a
. 当Haskell看到文字
0
和1
,由于数字文字被重载,它只决定一般类型: Num a => a
。 That means that the constraint Haskell infers is just 这意味着约束Haskell推断的只是
drawLine :: (Num n, MArray a n m) => ...
And this doesn't even need FlexibleInstances
since all constraints have arguments that are type variables. 这甚至不需要
FlexibleInstances
因为所有约束都具有类型变量的参数。
Just a thought based on my understanding - when you pass in a Char
value, it is already a 'specialised' type. 只是一个基于我理解的想法 - 当你传递一个
Char
值时,它已经是一个'专业'类型。 On the other hand, since you pass in numbers without explicitly typing, I believe that could be interpreted as passing a more general type ie (Num a) => a
. 另一方面,由于您在没有明确键入的情况下传入数字,我相信可以解释为传递更通用的类型,即
(Num a) => a
。 That is why GHC complains for explicit Char
literal, but not for the numbers. 这就是为什么GHC抱怨明确的
Char
字面,但不是数字。
Basing this off my understanding of the documentation here : 基于我对文档的理解基于此 :
Haskell computes a type for each variable bound by let or where, and then generalizes this type.
Haskell为let或where绑定的每个变量计算一个类型,然后概括这个类型。 In Haskell 98, the allowed contexts are restricted, so contexts are reduced using instance declarations (and duplicate assertions and those implied by class contexts are removed) until either they are in the allowed form or no instance is applicable, in which case an error is reported.
在Haskell 98中,允许的上下文是受限制的,因此使用实例声明减少了上下文(并且删除了重复的断言和类上下文隐含的那些),直到它们处于允许的形式或者没有适用的实例,在这种情况下错误是报道。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.