Haskell - 重叠实例和转换类型类
Haskell - Overlapping Instances and Conversion typeclass
我正在编写代码以在数理逻辑中实现 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
。当然这里不是这样的...
我该如何正确处理这个问题?提前致谢! ^_^
你在做正确的事。您对 Overlapping instances
警告保持谨慎是正确的。在这种情况下,它是连贯的。而且你不怕语言扩展,所以你想要:
instance {-# OVERLAPPABLE #-} (ToB a) => ToA a where
convertToA = convertToA . convertToB
{-# #-}
中的那个东西是 pragma,它是一种为调用语言扩展而量身定制的方式,仅适用于此实例。 OVERLAPPABLE
表示允许有一个更具体的实例(ToA B
),并根据偏好选择它。
你的约束(ToB a) =>
确实是Undecidable
因为它不小于实例头。与重叠相比,UndecidableInstances
是一个相对 'safe' 的扩展。
不安全的重叠使用是 INCOHERENT
(听起来很糟糕)或 'Orphan instances'——有时会给您一个编译器警告;不适用于此处,因为您的所有实例都与 class 声明位于同一模块中。
我正在编写代码以在数理逻辑中实现 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
。当然这里不是这样的...
我该如何正确处理这个问题?提前致谢! ^_^
你在做正确的事。您对 Overlapping instances
警告保持谨慎是正确的。在这种情况下,它是连贯的。而且你不怕语言扩展,所以你想要:
instance {-# OVERLAPPABLE #-} (ToB a) => ToA a where
convertToA = convertToA . convertToB
{-# #-}
中的那个东西是 pragma,它是一种为调用语言扩展而量身定制的方式,仅适用于此实例。 OVERLAPPABLE
表示允许有一个更具体的实例(ToA B
),并根据偏好选择它。
你的约束(ToB a) =>
确实是Undecidable
因为它不小于实例头。与重叠相比,UndecidableInstances
是一个相对 'safe' 的扩展。
不安全的重叠使用是 INCOHERENT
(听起来很糟糕)或 'Orphan instances'——有时会给您一个编译器警告;不适用于此处,因为您的所有实例都与 class 声明位于同一模块中。