【问题标题】:Lifting polymorphic values with typeclasses使用类型类提升多态值
【发布时间】:2015-03-21 20:25:39
【问题描述】:

我尝试将自动提升为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

但是,使用此方法只能提升单态值。这 yz 的定义产生类型错误:

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

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

【问题讨论】:

    标签: haskell typeclass


    【解决方案1】:

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

    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
    

    现在你所有的例子都可以工作了。

    【讨论】:

    • 比我删除的版本简单多了。
    猜你喜欢
    • 2021-03-16
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-17
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多