在 Haskell 中定义复合类型的实例

Defining an instance for a composite type in Haskell

我有一个类型具有类似 mappend 的功能,但不是真正的 mappend,因此它不是 Semigroup。例如:

data MyType = MyType Int deriving Show

myMerge :: MyType -> MyType -> Maybe MyType
myMerge (MyType x) (MyType y)
  | (x < 0) || (y < 0) = Nothing
  | otherwise          = Just $ MyType $ x + y

我总是处理 MyType 包裹在 Maybe 中的情况。如果我可以像这样在 "combined" 类型 Maybe MyType 上定义 Semigroup 实例,我需要能够完美表示的语义:

instance Semigroup (Maybe MyType) where
  (Just x) <> (Just y) = myMerge x y
  Nothing  <> Nothing  = Nothing
  Nothing  <> (Just _) = Nothing
  (Just _) <> Nothing  = Nothing

即当两个参数都是 Just 时,我可以得到 JustNothing,否则我总是得到 Nothing。但这是不可能的,我得到一个错误:

All instance types must be of the form (T a1 ... an)

如何表示我需要的语义?

您定义的实例是非法的,因为它基本上是在尝试为 Maybe 定义一个不同的(部分)Semigroup 实例,但 Maybe 已经有一个。相反,使用新类型包装器:

newtype MaybeMyType = MaybeMyType (Maybe MyType)

instance Semigroup MaybeMyType where
  ...

如果您想使用其 Semigroup 实例,则必须通过此 MaybeMyType 包装器与您的类型进行交互。