【问题标题】:How to write an instance for all types in another type class?如何为另一个类型类中的所有类型编写实例?
【发布时间】:2012-01-16 08:52:36
【问题描述】:

我必须定义一个类型类Truthy,其中包含一个方法true,将类型类的实例转换为Bool 值。

我的类型类声明:

class Truthy a where
    true :: a -> Bool

接下来,我必须为各种类型定义此类的实例,包括列表和数字类型。我已经为列表和Ints 完成了它,但是有没有办法同时为所有数字类型完成它?

基于我的 Int 声明:

instance Truthy Int where
    true = (/=) 0

我已经尝试添加类型类约束,但它不起作用:

instance (Num a) => (Truthy a) where
    true = (/=) 0::a

如果有一种类似于我的想法的方法,还是应该为每种数字类型分别定义它?

【问题讨论】:

标签: haskell


【解决方案1】:

这可能对家庭作业没有帮助,但您实际上可以编写这样的声明。您只需启用-XFlexibleInstances 即可。至少在 GHC 中,您可以通过在文件顶部放置一个 pragma 来做到这一点:

{-# LANGUAGE FlexibleInstances #-}

如果您仔细查看收到的错误消息,它会说“如果您想禁用它,请使用 -XFlexibleInstances。”。

在这种特殊情况下,您还需要启用UndecidableInstancesOverlappingInstances

 {-# LANGUAGE FlexibleInstances,  UndecidableInstances, OverlappingInstances #-}

您需要FlexibleInstances,因为标准Haskell 不允许类型变量在头部多次出现的任何形式的实例。这完全没问题——我是最常用的扩展之一(根据this question)。

您需要UndecidableInstances,因为您的实例声明可能会导致类型检查器永远循环。我认为使用UndecidableInstances 可以通过限制在尝试减少实例时检查的深度来防止这种情况。这通常——包括在这种情况下——很好,但理论上可以使特定程序是否通过类型检查依赖于实现。不过,它应该适用于您的情况。

正如 hammar 所指出的,您需要启用OverlappingInstances,因为在检查它们是否重叠时,实例的“上下文”被忽略。在这种情况下,上下文是Num a 位。因此,用于检查是否重叠的实例被读取为instance Truthy a... 并与所有内容重叠。启用 OverlappingInstances 后,您只需拥有一个最具体的实例即可。

【讨论】:

  • 我在错误日志中看到了。很高兴能解释为什么我需要启用任何额外的功能才能编译它,或者至少在我可以阅读的地方。另外,这是做我想做的唯一方法吗?
  • 基本上,Haskell 98 报告指定类声明必须是“简单的”。所以 standard Haskell 不允许您尝试使用的样式(除非它在 ​​2010 年更改?)。但是你写的代码其实是合理的,可以实现的,所以GHC支持;您需要 pragma 的原因是它不在标准中。
  • 如果您想了解更多信息,请参阅文档herehere
  • 如果您想要除数字之外的任何实例,您还需要OverlappingInstances,因为它与所有内容重叠。这是因为实例头是a,它匹配任何东西。 Num 约束直到之后才会被检查。
  • @TikhonJelvis:定义实例没问题,但您是否尝试过实际使用它们?
猜你喜欢
  • 2015-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 2021-03-22
相关资源
最近更新 更多