简体   繁体   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

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的一部分)。

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

相关问题 使用FlexibleContexts和FlexibleInstances有哪些陷阱? - What are the pitfalls of using FlexibleContexts and FlexibleInstances? 使用 STArray 的两个几乎相同的函数:为什么一个需要 FlexibleContexts,而另一个不需要? - Two almost identical functions using STArray: why does one requires FlexibleContexts, and the other does not? 在没有FlexibleContexts的情况下为Data.Functor.Compose编写Show实例 - Writing a Show instance for Data.Functor.Compose without FlexibleContexts FlexibleContexts 扩展有什么用? 你能用一个简单的例子解释一下吗? - What is the FlexibleContexts extension good for? Could you please explain it using a simple example? 在这种情况下真的需要 FlexibleContexts 吗? - Is FlexibleContexts really needed in this context? 为什么列表推导在Haskell中没有错误地接受混合的`[Char]`和`[[Char]]`? - Why does a list comprehension accept mixed `[Char]` and `[[Char]]` without error in Haskell? 为什么这段代码使用UndecidableInstances编译,然后生成运行时无限循环? - Why does this code using UndecidableInstances compile, then generate a runtime infinite loop? putStrLn,类型Char不匹配[Char] - putStrLn, type Char does not match [Char] 持续更新无法编译 - Persistent upsert does not compile 如何在不安装的情况下编译 haskell package? - How to compile a haskell package without installation?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM