【问题标题】:type families: how to instantiate Bifunctor for a pair data type family?类型族:如何为一对数据类型族实例化 Bifunctor?
【发布时间】:2016-04-15 08:19:18
【问题描述】:

我试图了解如何使用数据类型族来隐藏构造函数。给出的简单示例是具有从普通对转换为普通对等操作的对。 bifunctor 的实例无法编译;错误信息是

src/TypeFamilyTest.hs:66:21: Bifunctor 的第一个参数应该有一种* -> * -> *, 但是Pairs a b 有种ghc-prim-0.4.0.0:GHC.Prim.Constraint

Bifunctor (Pairs a b)的实例声明中

尝试Bifunctor Pair where ... 我收到另一条错误消息,其中列出了相同的GHC.Prim.Constraint。实例的正确参数是什么?上下文将如何传递?

class  Pairs a b where
    data Vec2 a b  

    mkPair :: (a,b) -> Vec2 a b   -- (FirstF a, SecondF a) -> a
    splitPair :: Vec2 a b -> (a,b)
    fstP ::  Vec2 a b -> a
    sndP ::  Vec2 a b -> b
    fstP = fst . splitPair
    sndP = snd . splitPair

instance ( ) => Bifunctor (Pairs a b) where
     bimap opv oph vh = mkPair  (opv . fstP $ vh, oph . sndP $ vh)

【问题讨论】:

  • 数据族不是隐藏构造函数。它们的构造函数可以以与普通数据类型相同的方式可见或隐藏。数据族是关于非参数数据类型的——类型在决定它们的构造函数是什么样子之前检查它们的类型参数。
  • 类型类不是面向对象意义上的类。它不封装数据和对其进行的操作。
  • Haskell class 的最接近 OOP 概念是类似于 Java 的 interface,甚至这种对应关系也是松散的。
  • 你可以定义一个类型newtype Vec2' a b = Vec2' (Vec2 a b),你可以为这个类型创建类型类的实例来满足你的需求。但是,这种类型不是Bifunctorbimap 的类型将是 (Pairs a b, Pairs a' b') => (a -> a') -> (b -> b') -> Vec2' a b -> Vec2' a' b'
  • 感谢您的澄清。我不明白你为什么要引入一个新类型。 Vec2 和 Vec2' 有什么区别?都有两个参数?额外的包装器有什么好处?

标签: haskell type-families


【解决方案1】:

类型错误告诉你一切。 Pair 不是数据类型的名称。它是一个类的名称。 Pair a b :: Constraint 所以Pair :: * -> * -> ConstraintBifunctor 只能由 * -> * -> * 类型的数据类型实例化。

我猜你的意思可能是这样的:

newtype Pair a b = Vec2 { splitPair :: (a, b) }

fstP :: Pair a b -> a
fstP = fst . splitPair

sndP :: Pair a b -> b
sndP = snd . splitPair

instance Bifunctor Pair where
    bimap f g (Vec2 (x, y)) = Vec2 (f x, g y)

我不明白您为什么最初将 Vec2 设为关联类型。我怀疑这可能是XY problem - 你真正想要达到什么目的?

【讨论】:

  • 看起来 OP 正在尝试模拟面向对象的编程,Pairs 是一种封装了Vec2 的类型。巧合的是,他们的尝试在语法上是正确的。
  • 感谢您提供的有用答案。我试图减少程序中的混乱,我觉得我有太多的类并开始尝试相关类型。我现在更好地理解了,哪些关联类型是有用的,并将使用建议的解决方案。 - 谢谢!
猜你喜欢
  • 2014-10-02
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 2018-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
相关资源
最近更新 更多