是否有可能在Haskell中使(a,a)成为类型类的成员

时间:2015-09-15 18:57:37

标签: haskell

这是Haskell中的代码:

class Fooable a where
    foo :: a -> a

instance Fooable (a, a) where 
    foo = ...

这样的代码无法在没有FlexibleInstances扩展名的传统Haskell中编译。错误消息会说:

Illegal instance declaration for ‘Fooable (a, 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 ‘Fooable (a, a)’

问题是,实际上不可能使元组(a, a)成为任何类型类的成员,因为each type variable appears at most once in the instance head

2 个答案:

答案 0 :(得分:6)

没有办法在实例中直接强制(a, b)的关系(没有FlexibleInstances或其他扩展名),但它们可能是等效的。

这意味着,如果Fooable (a, b)是一个实例,那么如果a可以等于b,则Fooable (a,a)也是一个实例。考虑获得更多实例。

然而,有一些方法:

newtype Tuple a = Tuple {unTuple :: (a, a)}

instance Fooable (Tuple a) where
    foo = id

它不是这个星球上最漂亮或最好的东西,但至少在运行时它会表现得好像没有包装。

答案 1 :(得分:6)

如果您想使用其他扩展程序,可以编写

{-# LANGUAGE GADTs #-}
-- and/or
{-# LANGUAGE TypeFamilies #-}

instance a ~ b => Fooable (a, b) where
  foo (a, b) = (b, a)

这将使Fooable (a, a)成为实例,并确保没有其他对可以是实例(没有OverlappingInstances)。然而,AJFarmar's answer对此有一种更愉快的感觉。