繁体   English   中英

如果没有FlexibleContexts,使用Char不会编译

[英]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看到文字01 ,由于数字文字被重载,它只决定一般类型: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM