【问题标题】:Haskell "not" type constraintHaskell“非”类型约束
【发布时间】:2012-03-21 23:53:33
【问题描述】:

我正在尝试以归纳方式定义一对类实例。那就是:

class Foo a b | a -> b where
  foo :: a -> b

instance (not?)Foo a => Bar a b
  foo x = ...

instance Foo a => Bar a b
  foo x = ...

第一个实例确定基本操作,第二个实例递归调用 foo。有没有办法做到这一点?一个很好的例子是展平一个列表,在第一种情况下它是标识函数,在第二种情况下它是 concat 的递归应用。

【问题讨论】:

  • 请注意,在 Haskell 中,不可能确定给定类型 不是 给定类型类的实例,因为其他人可以用一些提供实例的他们自己的代码。

标签: haskell types


【解决方案1】:

没有办法直接执行此操作,原因很简单——实例选择只查看“头部”,即=> 之后的部分。您在上下文中放置的任何内容(=> 之前的部分)都不会影响选择哪个实例。

对于简单的情况,您通常可以完全避免该问题,例如“基本情况”类型的数量有限。一个常见的例子是类型级别的列表,其中你有一个 Cons 的递归案例和一个 Nil 的基本案例,就是这样。

在一般情况下,您通常需要某种“条件测试”类型类,该类根据是否满足某些条件来选择类型,然后将实际实现移交给采用条件的“助手”类结果值作为参数并使用它来选择实例。

【讨论】:

  • 那么你将如何实现一个通用列表展平类成员?
  • 嗯,最诚实的回答是我不会。在我看来,如果不破坏多态输入,就没有办法做到这一点,而且它不足以证明麻烦是合理的。也就是说,对于扁平化列表,我认为您可以仅依靠重叠实例在递归与基本情况之间进行选择。你在这里使用OverlappingInstances 吗?您可能会以一种或另一种方式需要它。
  • 为什么需要一个通用的列表展平功能?它很少有用。
【解决方案2】:

这是一个implementation of a flatten function,适用于任何级别的嵌套列表。不过我真的不推荐使用它——这里只是为了演示如何在 haskell 中实现类似的功能。

【讨论】:

  • 使用 IncoherentInstances 会招来麻烦。
  • @augustss,非常正确,因此我将免责声明放在了顶部。我认为没有IncoherentInstances 就不可能实现flatten(这可能是一个很好的迹象,表明设计一个依赖这个函数的程序是一个坏主意)。
  • @is7s:那里的解决方案无法派生扁平列表的类型(因此您必须将其指定为flatten [[3],[4]] :: [Int]。为此,您需要提供三个扩展名。它是不过,这可能是一个值得的权衡。
  • 上述解决方案不适用于 ghc 7.4.1。上述解决方案也至少缺少 2 个扩展。
  • 我很想知道为什么 ghc 7.4.1 不支持它。 ghc 7.2.1 也不支持它。这些版本的哪些更改停止了对该声明的支持?我会尝试找到更多关于它的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-06
  • 1970-01-01
  • 2013-08-19
  • 2013-11-05
  • 2013-05-31
  • 2021-03-18
  • 2017-04-11
相关资源
最近更新 更多