混合类型类和类型族时出现问题

时间:2010-04-07 06:44:48

标签: haskell typeclass type-families

此代码编译良好:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
  UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
  TypeOperators, TypeSynonymInstances, TypeFamilies #-}
class Sel a s b where
  type Res a s b :: *

instance Sel a s b where
  type Res a s b = (s -> (b,s))

instance Sel a s (b->(c,a)) where
  type Res a s (b->(c,a)) = (b -> s -> (c,s))

但是一旦我添加R谓词ghc失败:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
  UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
  TypeOperators, TypeSynonymInstances, TypeFamilies #-}
class Sel a s b where
  type Res a s b :: *

instance Sel a s b where
  type Res a s b = (s -> (b,s))

class R a where
  type Rec a :: *
  cons :: a -> Rec a
  elim :: Rec a -> a
instance Sel a s (b->(c,Rec a)) where
  type Res a s (b->(c,Rec a)) = (b -> s -> (c,s))
抱怨:

    Illegal type synonym family application in instance:
        b -> (c, Rec a)
    In the instance declaration for `Sel a s (b -> (c, Rec a))'

它是什么意思和(最重要的)我该如何解决它?

由于

3 个答案:

答案 0 :(得分:12)

类型系列是单向的:您可以将Rec a扩展为其计算类型,但不能(唯一地)从扩展回到Rec a。这使得类型函数的应用程序不适合签名,因为它们永远不会触发实例应用。

您可以尝试改为:

instance Rec a ~ reca => Sel a s (b->(c,reca))

这意味着别的东西:它表示任何函数b -> (c, reca)都是一个实例,然后当它不可撤销地匹配时,编译器会检查Rec a ~ reca。但在你的情况下,这可能足够好了。

答案 1 :(得分:1)

Rec不是类型构造函数;这是一种类型功能。也许你只能在类型定义的值类型中使用它,而不是在类声明中?我在这里疯狂地猜测;我不了解类型系列的所有规则。

我不知道如何修复它,但有些事情要尝试包括:

  • 摆脱类Sel并定义type family Res a s b :: *。使用type instance代替类机制。

  • 使用Rec制作类型data几乎不可能有所帮助,但我不这么认为。

  • 缩减到可能有效的最少数量的语言扩展 - 这将使其他人更容易为您提供帮助,它也可能对编译器有所帮助。

答案 2 :(得分:1)

这意味着在声明类型实例时不允许使用类型同义词系列。请参阅GHC手册的"Type families and instance declarations"部分。

你可以解决它的唯一方法是重构,以便不需要它。