2

我正在阅读来自第一原理的 Haskell Programming 一书,本章中有一个练习newtype,要求我TooMany(Num a, TooMany a) => (a, a).

之前的练习已经为、和提供了TooMany实例。我已经完成了这些,但不是为了.IntGoats Int(Int, String)(Int, Int)(Num a, TooMany a) => (a, a)

所有代码如下:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances #-}

class TooMany a where
  tooMany :: a -> Bool

instance TooMany Int where
  tooMany n = n > 42

newtype Goats = Goats Int deriving (Eq, Show, TooMany)

-- the following needs FlexibleInstances pragma
instance TooMany (Int, String) where
  tooMany (n, _) = n > 33

-- or do this:
newtype AnotherTooMany = AnotherTooMany (Int, String) deriving (Eq, Show, TooMany)

instance TooMany (Int, Int) where
  tooMany (n, m) = (n + m) > 44


-- THE FOLLOWING ONES ARE NOT CORRECT !!!

instance TooMany (Num a, TooMany a) => (a, a) where
  tooMany (t1, t2) = (t1 + t2) > 44

newtype YetAnotherTooMany =
  YetAnotherTooMany (Num a, TooMany a) => (a, a)
  deriving (Eq, Show, TooMany)

我应该如何更改最后两个表达式以使它们起作用?

我还提到了以下问题,但仍然没有找到答案:

向 typeclass 实例添加类约束

可以在新类型定义中使用类型类约束吗?

4

1 回答 1

1

最小的变化是这样的:

instance (Num a, Ord a, TooMany a) => TooMany (a, a) where
    tooMany (t1, t2) = (t1 + t2) > 44

Ord关于此实例的两个注意事项:由于对 的调用,我必须添加一个约束(>),并且该TooMany约束是多余的,因为该实现不tooMany使用 aa作为参数进行调用。我怀疑预期的练习解决方案对该方法的实现略有不同tooMany——我鼓励您尝试找到一种使用TooMany a约束而不使用Ord a约束来实现它的方法!

对于您的newtype,正确的语法是这样的:

newtype YetAnotherTooMany a = YetAnotherTooMany (a, a)
    deriving (Eq, Show, TooMany)

您需要删除的(Int, Int)实例TooMany才能使这种确切的语法起作用,否则在派生过程中会有重叠的实例可供选择。但是,我希望预期的练习解决方案是在该实例根本不存在newtype的假设下为此自己编写实例——因为大概目标是首先学习如何使用以避免重叠的实例问题。(a, a)newtype

于 2018-10-12T13:49:10.827 回答