【问题标题】:Type parameters constraints for instances of typeclasses with kind * -> *类型参数约束类型类实例的类型 * -> *
【发布时间】:2012-09-20 06:26:28
【问题描述】:

假设我有Heap a 类型,其中Heap 是类型* -> * 的类型构造函数。堆上的许多基本操作都要求 a 类型是 Ord 类型类的实例。

data Heap a = ...

findMin :: Ord a => Heap a -> a
deleteMin :: Ord a => Heap a -> Heap a

只要a 类型参数是Ord 类型类的实例,我想将我的Heap 类型声明为Foldable 类型类的实例(通过findMindeleteMin 函数)。

当我们处理需要* 类型的类型类时,可以轻松表达这种关系,例如Show

instance Show a => Show (Heap a) where
    show h = ...

但我在声明Foldable 时遇到问题:

instance Foldable Heap where
    -- Ouch, there is no `a` type parameter to put the constraint on!
    foldr f z h = ...

是否可以在此类实例声明中对a 类型参数施加约束?

【问题讨论】:

  • 看看this stuff。他们正在用 monad 做类似的事情。
  • 非常感谢您的链接,ConstraintKind真的有趣的东西!
  • 顺便说一句,findMin 真的需要Ord 实例吗?
  • 一些实现(比如我在下面展示的基于慢速列表的实现)不需要对findMin 进行Ord 约束,但其中一些实现(比如Okasaki 描述的SkewBinominalHeap)需要该约束.我想在现实生活中Heap 应该是在findMin 上具有Ord 约束的类型类。

标签: haskell typeclass


【解决方案1】:

一般来说,不,当类型构造函数本身被赋予实例时,没有办法限制它所应用的类型。大多数情况下这是一件好事,因为它可以确保例如Functor 实例真正不知道它们的元素类型,这有助于保持良好且可预测的行为良好且可预测。

有时这反而令人烦恼,最常见的例子确实需要一个 Ord 约束来用于排序数据结构,否则它可能是一个很好的、表现良好的实例。

有一些实验性技术涉及诸如约束类型之类的东西,但在您的具体情况下,已经有一个可行的解决方案。如果你看Foldable的定义,它说只有foldMapfoldr需要实现,所以我们会考虑这些。注意类型:

foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
foldr :: (Foldable t) => (a -> b -> b) -> b -> t a -> b

在这两种情况下,带有Foldable 实例的类型只出现一次,作为函数的参数。因此,您可以使用 use GADTs 约束 Ord

data Heap a where
    Heap :: (Ord a) => ...

通过这样做,您在任何时候创建 Heap 值(甚至是空堆)都需要一个Ord 实例;但是当您接收 Heap 值时,其上的模式匹配会将 Ord 实例带回作用域——即使在 Foldable 实例内!

请注意,这在许多其他情况下无济于事:

fmap :: (Functor f) => (a -> b) -> f a -> f b

在这里,我们可以在a 上获得一个Ord 实例,但我们还需要一个用于b 的实例,这是不可能的。

return :: (Monad m) => a -> m a

这里我们还需要提供一个Ord 实例。

【讨论】:

  • 谢谢你,我搞定了,我已经准备了小样本如何做到这一点:ideone.com/HWl7H。这对我来说看起来很奇怪,但我们不能像这样在类型声明中使用约束:newtype Ord a => ListHeap a = LH [a]。这不适用于Foldable 实例。我们真的必须使用带有模式匹配的 GADTs 扩展。非常感谢您的回答!
  • @roman-kashitsyn:是的,有/曾经有类似常规数据类型的语法,但它没有做同样的事情,是一个完全无用的错误功能,可能会从最终的语言标准(除非它已经是并且我忘记了)。
【解决方案2】:

查看 Hackage 上的 keys 库。检查它的FoldableWithKey 类型类是否是您需要的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-02
    • 2018-06-15
    • 2012-09-06
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 2017-11-28
    • 1970-01-01
    相关资源
    最近更新 更多