用类型类提升多态值

时间:2015-03-21 11:33:01

标签: haskell typeclass

我尝试将自动提升实现为Either类型:纯值将是 已使用Right提升Eitherid-- Wrapper for pure, non-Either values newtype ConstRight a = ConstRight a class LiftEither t e a where liftEither :: t -> Either e a instance LiftEither (Either e a) e a where liftEither = id instance LiftEither (ConstRight a) e a where liftEither (ConstRight a) = Right a x :: Either () (Int -> Int) x = liftEither $ ConstRight (id :: Int -> Int) y :: Either () (a -> a) y = liftEither $ ConstRight id z :: Either (a -> a) () z = liftEither $ Left id

y

然而,使用这种方法只能提升单一值。该 zNo instance for (LiftEither (ConstRight (a1 -> a1)) () (a -> a)) arising from a use of ‘liftEither’ The type variable ‘a1’ is ambiguous No instance for (LiftEither (Either (a0 -> a0) b0) (a -> a) ()) arising from a use of ‘liftEither’ The type variables ‘b0’, ‘a0’ are ambiguous 的定义产生类型错误:

ConstRight a

这可以通过功能依赖来解决,但e不能确定class LiftEither t e a | t -> e a where liftEither :: t -> Either e a

ConstRight

我也尝试使用相关类型,但我无法想出合适的类型 class LiftEither t where type Result t liftEither :: t -> Result t instance LiftEither (Either e a) where type Result (Either e a) = Either e a liftEither = id instance LiftEither (ConstRight a) where type Result (ConstRight a) = Either e a -- e is not in scope liftEither (ConstRight a) = Right a 实例的定义:

{{1}}

是否可以为多态值实现这一点?

1 个答案:

答案 0 :(得分:3)

您应该始终将尽可能多的信息从实例头移动到实例约束。在这里,可以纯粹基于我们是Either还是ConstRight来确定正确的实例,因此不需要进一步约束实例头。

LiftEither (Either e a) e a过于严格,因为它要求在匹配实例头时可以确定两个a - s和两个e - s相等。另一个实例有同样的问题。相反,您应该将类​​型等式移动到约束。这样,GHC可以愉快地匹配实例并尝试稍后解决约束。

{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}

newtype ConstRight a = ConstRight a

class LiftEither t e a where
  liftEither :: t -> Either e a

instance (e ~ f, a ~ b) => LiftEither (Either e a) f b where
  liftEither = id

instance (a ~ b) => LiftEither (ConstRight a) e b where
  liftEither (ConstRight a) = Right a

现在你的所有例子都有效。