我有一个类,它有一个类似于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
中时,我总是需要处理它。如果我能够在"组合"类型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
时,我可以得到Just
或Nothing
,否则我总是得到Nothing
。但是这是不可能的,我会遇到错误:
All instance types must be of the form (T a1 ... an)
我应该如何表示所需的语义?
myMerge
的定义肯定无法编译 - 参数应该是MyType x
和MyType y
? - Robin ZigmondtoMyType :: Int -> Maybe MyType
,如果参数小于0,则返回Nothing
。否则,我建议不要试图将你的类型适应不支持它的接口 - 将其定义为自由函数是惯用的方式。(最后注意你的<>
定义只是liftA2 myMerge
- 在需要时直接内联编写可能更容易) - user2407038liftA2 myMerge
。那需要myMerge
的签名是MyType -> MyType -> MyType
。但是,即使给出两个 Justs,myMerge
也可以选择返回 Nothing,这是完全不同的事情。 - amalloyMaybe
包装过的MyType
,那么也许将Maybe
作为MyType
的一部分会更好? - luqui