Haskell 使用TypeClass提升多态值

Haskell 使用TypeClass提升多态值,haskell,typeclass,Haskell,Typeclass,我试图实现自动提升到类型中的任一类型:纯值 使用右侧解除,已使用id值解除 -- 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

我试图实现自动提升到
类型中的任一类型:纯值
使用
右侧
解除,已使用
id
解除

-- 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
z
产量类型错误的定义:

No 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

是否可以为多态值实现此功能?

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

LiftEither(ea)ea
过于严格,因为它要求两个
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

现在,您所有的示例都可以使用。

比我删除的版本简单得多。