![](/img/trans.png)
[英]What are the pitfalls of using FlexibleContexts and FlexibleInstances?
[英]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
但是将数组类型从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
有人可以澄清为什么会这样吗?
谢谢。
原因实际上是在错误消息中。
Non type-variable argument in the constraint:
MArray a0 Char m (Use FlexibleContexts to permit this)
当您使用文字'_'
和'1'
,Haskell推断它们的类型是Char
,然后它会遇到MultiParamTypeClasses
约束所带来的最典型问题 - 约束参数不是所有类型变量,但是是Haskell报告要求它们。 签名Haskell 想要推断的是类似的东西
drawLine :: MArray a Char m => ...
这在MultiParamTypeClasses
之前不是问题,因为之前的所有类只有一个参数。 然后,如果该参数不是类型变量,那么您所要做的就是检查该实例是否是可派生的,如果它是类型变量,则将其保留为约束。 使用MultiParamTypeClasses
您经常会遇到中间情况 - 某些参数是实例化的,有些则不是。 FlexibleContexts
让你有这种混合(甚至更多)。 这是一个安全的扩展(我希望看到它成为Haskell 2020的一部分)。
Int
呢? 为什么不给我同样的错误? 它实际上不是直接关于Int
。 当Haskell看到文字0
和1
,由于数字文字被重载,它只决定一般类型: Num a => a
。 这意味着约束Haskell推断的只是
drawLine :: (Num n, MArray a n m) => ...
这甚至不需要FlexibleInstances
因为所有约束都具有类型变量的参数。
只是一个基于我理解的想法 - 当你传递一个Char
值时,它已经是一个'专业'类型。 另一方面,由于您在没有明确键入的情况下传入数字,我相信可以解释为传递更通用的类型,即(Num a) => a
。 这就是为什么GHC抱怨明确的Char
字面,但不是数字。
基于我对文档的理解基于此 :
Haskell为let或where绑定的每个变量计算一个类型,然后概括这个类型。 在Haskell 98中,允许的上下文是受限制的,因此使用实例声明减少了上下文(并且删除了重复的断言和类上下文隐含的那些),直到它们处于允许的形式或者没有适用的实例,在这种情况下错误是报道。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.