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

cro*_*ser 7 haskell typeclass

我有一个具有类似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
Run Code Online (Sandbox Code Playgroud)

我总是MyType在包裹时处理它Maybe。如果我可以像这样Semigroup在“组合”类型上定义实例,我需要可以完美表示的语义Maybe MyType

instance Semigroup (Maybe MyType) where
  (Just x) <> (Just y) = myMerge x y
  Nothing  <> Nothing  = Nothing
  Nothing  <> (Just _) = Nothing
  (Just _) <> Nothing  = Nothing
Run Code Online (Sandbox Code Playgroud)

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

All instance types must be of the form (T a1 ... an)
Run Code Online (Sandbox Code Playgroud)

如何表达我需要的语义?

ama*_*loy 9

The instance you defined is illegal because it is basically trying to define a different (partial) Semigroup instance for Maybe, but Maybe already has one. Instead, use a newtype wrapper:

newtype MaybeMyType = MaybeMyType (Maybe MyType)

instance Semigroup MaybeMyType where
  ...
Run Code Online (Sandbox Code Playgroud)

You will have to interact with your type through this MaybeMyType wrapper in the cases where you want to use its Semigroup instance.