Haskell-重叠实例和转换类型类

问题描述 投票:0回答:1

我正在编写代码以用数学逻辑实现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),则该错误更有意义。当然,这里不是这种情况...

我应该如何正确处理此问题?提前致谢! ^ _ ^

haskell types typeclass overlapping-instances
1个回答
0
投票

您正在做正确的事情。您应该对Overlapping instances警告保持谨慎。在这种情况下,它是连贯的。而且您不担心语言扩展,因此您需要:

instance {-# OVERLAPPABLE #-} (ToB a) => ToA a where
  convertToA = convertToA . convertToB

{-# #-}中的那个东西是一种杂注,这是仅针对此实例调用语言扩展的一种紧密定制的方法。 OVERLAPPABLE表示允许存在一个更具体的实例(ToA B),并根据喜好选择该实例。

您的约束(ToB a) =>的确是Undecidable,因为它不小于实例头。与重叠相比,UndecidableInstances是相对“安全”的扩展名。

带有重叠部分,不安全的用法是INCOHERENT(听起来很糟糕)或“孤立实例”-有时会向您发出编译器警告;在这里不适用,因为您的所有实例都与类声明在同一个模块中。

© www.soinside.com 2019 - 2024. All rights reserved.