我正在编写代码来实现数理逻辑中的extension by definitions。
它接受语言及其扩展的描述,并输出一个新的haskell文件,该文件将高级语言解析为低级语言。当然,如果我能把C语言变成B语言,B语言变成A语言,那么通过作曲,我就能把C变成A……然而。
以下是我面临的问题的一个最小示例:
data A = EmptyA | NodeA A A
data B = EmptyB | NodeB B B | UnaryB B
data C = EmptyC | NodeC C C | UnaryC C | TernaryC C C C
class ToA a where
convertToA :: a -> A
class ToB a where
convertToB :: a -> B
instance ToA B where
convertToA EmptyB = EmptyA
convertToA (NodeB l r) = NodeA (convertToA l) (convertToA r)
convertToA (UnaryB l) = NodeA (convertToA l) EmptyA
instance ToB C where
convertToB EmptyC = EmptyB
convertToB (NodeC l r) = NodeB (convertToB l) (convertToB r)
convertToB (UnaryC l) = UnaryB (convertToB l)
convertToB (TernaryC l m r) = NodeB (convertToB l) (NodeB (convertToB m) (convertToB r))
-- instance (ToB a) => ToA a where
-- convertToA = convertToA . convertToB
-- I shouldn't have to write this
instance ToA C where
convertToA = convertToA . convertToB直观地说,instance (ToB a) => ToA a没有问题,但是编译器不喜欢它。代码按原样正确编译,但在用注释版本替换显式ToA C实例时,我收到以下错误:
minimal.hs:25:21: error:
• Illegal instance declaration for ‘ToA a’
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use FlexibleInstances if you want to disable this.)
• In the instance declaration for ‘ToA a’
|
25 | instance (ToB a) => ToA a where
| ^^^^^当然,我并不害怕语言扩展,所以我照我说的做,添加了FlexibleInstances,尽管我认为它在这里不应该有什么帮助。做完这件事后,我被告知要尝试UndecidableInstances...这就是线索停止的地方。我仍然收到一个类型错误,但我不确定如何处理它。
minimal.hs:29:16: error:
• Overlapping instances for ToA B
arising from a use of ‘convertToA’
Matching instances:
instance ToB a => ToA a -- Defined at minimal.hs:28:10
instance ToA B -- Defined at minimal.hs:16:10
• In the first argument of ‘(.)’, namely ‘convertToA’
In the expression: convertToA . convertToB
In an equation for ‘convertToA’:
convertToA = convertToA . convertToB
|
29 | convertToA = convertToA . convertToB
| ^^^^^^^^^^这个错误消息让我特别困惑,因为我对ToA B只有一个定义。如果B本身是ToB的一个实例,比如通过设置convertToB = id,那么这个错误会更有意义。当然,这里不是这样的。
我该如何正确处理这个问题呢?提前感谢!^_^
发布于 2020-04-27 10:12:42
你做的事情是对的。您对Overlapping instances警告保持谨慎是正确的。在这种情况下,它是连贯的。而且你不怕语言扩展,所以你想:
instance {-# OVERLAPPABLE #-} (ToB a) => ToA a where
convertToA = convertToA . convertToB{-# #-}中的东西是编译指示,这是一种为调用语言扩展而量身定制的方法,仅针对此实例。OVERLAPPABLE意味着允许存在更具体的实例(ToA B),并根据偏好进行选择。
您的约束(ToB a) =>确实是Undecidable,因为它不小于实例头部。与重叠相比,UndecidableInstances是一个相对“安全”的扩展。
对于重叠,不安全的用法是INCOHERENT (就像听起来那么糟糕)或‘孤立实例’--它们有时会给你一个编译器警告;在这里不适用,因为你所有的实例都与类声明在同一个模块中。
https://stackoverflow.com/questions/61448137
复制相似问题