【问题标题】:How does Haskell differentiate between difference possible type class instancesHaskell 如何区分不同的可能类型类实例
【发布时间】:2014-05-07 16:18:13
【问题描述】:

抱歉,如果我使用了错误的名称。我的问题来自对比 Scala 和 Haskell 语法。考虑:

class Monoid a where
  mempty :: a
  mappend :: a -> a -> a

instance Monoid Int where 
  mempty = 0
  mappend a b = a + b

sigma :: (Monoid a) => Int -> Int -> (Int -> Int) -> (Int -> a) -> a
sigma a b inc comp =
  if a > b then mempty else mappend (comp a) (sigma (inc a) b inc comp)

在 Scala 中可能是这样的:

trait Monoid[A] {
  def mempty: A
  def mappend(a1: A, a2: A): A
}

class IntMonoid extends Monoid[Int] {
  def mempty = 0
  def mappend(a: Int, b: Int) = a + b
}

def sigma[A](a: Int, b: Int, inc: Int => Int, comp: Int => a)
            (implicit m: Monoid[A]): A =
  if (a > b) m.mempty else m.append(comp(a), sigma(inc(a), b, inc, comp))

现在,Int 可以是带有 0 和加法的 Monoid,也可以是带有 1 和乘法的 Monoid,因此我们可以提供 2 个类型类,每个实现一个。在 Scala 中,如果两个实现都隐含在作用域内并且具有相同的优先级,这将导致编译错误。在这种情况下,我们可以简单地手动传递正确的实例,错误就会得到解决。

在这种情况下,Haskell 等价物是什么?如果有两个 Int 是 Monoid 的实例,如何选择使用哪个实现?

【问题讨论】:

  • 一个无关紧要的吹毛求疵:如果您想将 Int,*,1 视为幺半群,则无需排除零。
  • 你说得对,是在考虑组。更正了问题,谢谢!

标签: scala haskell typeclass


【解决方案1】:

Haskell 简单地为实际上是Num(包括Int 类型)类型类实例的任何类型提供了两个新类型包装器:SumProduct。所以,Sum 是加法下的幺半群,Product 类型是乘法下的幺半群。取自实际来源:

newtype Sum a = Sum { getSum :: a }
        deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num)

instance Num a => Monoid (Sum a) where
        mempty = Sum 0
        Sum x `mappend` Sum y = Sum (x + y)

newtype Product a = Product { getProduct :: a }
        deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num)

instance Num a => Monoid (Product a) where
        mempty = Product 1
        Product x `mappend` Product y = Product (x * y)

【讨论】:

  • 而且由于 newtype 是空操作,所有 SumProduct 构造函数都被编译掉了。
【解决方案2】:

在 Haskell 的一个模块中,不能有相同类型和类型类的两个实例。如果您在两个不同的模块中有两个实例,然后导入这两个模块,尝试使用该实例将导致编译错误。

因此,选择使用哪个实例的唯一方法是仅导入一个提供该实例的模块。

【讨论】:

  • 但请务必指出这是全球性的事情。如果您的任何依赖项导入了提供实例的模块,那么您也可以看到它。
  • 这就是孤儿实例被看不起的原因。如果仅在 1) 定义数据类型时或 2) 在定义类时定义实例,则可以保证不能为同一数据类型定义两个不同的实例。
猜你喜欢
  • 2016-08-12
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 2016-12-05
相关资源
最近更新 更多