monoidal mappend 的自动传播
Automatic propagation of monoidal mappend
假设我定义了一个幺半群:
data TotalLine = TotalLine { totalQuantity :: Int, orderTotal :: Float }
instance Monoid TotalLine where
mempty = zero
mappend = add
因为 totalQuantity 和 orderTotal 都是数字,所以它们在 (+)[=23= 下也形成一个幺半群]
有没有办法定义
add :: TotalLine -> TotalLine -> TotalLine
所以,我可以只在每个字段上传播 mappend 调用,而不必手动定义类似
的内容吗
add line1 line2 =
TotalLine {
totalQuantity = totalQuantity line1 + totalQuantity line2,
orderTotal = orderTotal line1 + orderTotal line2
}
有 generic-deriving
个包裹完全符合您的要求:
{-# LANGUAGE DeriveGeneric #-}
import Generics.Deriving.Monoid
import GHC.Generics
data T = T {str :: String, str' :: String}
deriving (Generic, Show)
main = undefined
instance Monoid T where
mempty = memptydefault
mappend = mappenddefault
还有一些来自 ghci 的结果:
> T "a" "b" `mappend` T "c" "d"
< T {str = "ac", str' = "bd"}
但是对于您的 TotalLine
数据类型,它不是开箱即用的,因为 Int
和 Float
都没有 Monoid
的实例.
还添加一个依赖项只是为了这个目的不太经济。您最好手动实现 Monoid
实例。
关于为什么 GHC 不能派生 Monoid 实例已经some discussion,结果证明通常这样的派生实例可能不是唯一的。但是在数据类型只有的特殊情况下一个具有具体和幺半群字段的构造函数派生实例是唯一的。
请注意,有几个具有域 Int 的幺半群(Nat、Float、..)
所以我会发现阅读具有 instance Monoid Int
的代码非常混乱。然后 mappend
可以是加号、乘号、最大值、最小值等等中的任何一个。
如果你可以稍微改变一下类型(但它仍然与你的同构),你可以试试这个:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Monoid
newtype TotalLine = TotalLine (Sum Int, Sum Float) deriving Monoid
假设我定义了一个幺半群:
data TotalLine = TotalLine { totalQuantity :: Int, orderTotal :: Float }
instance Monoid TotalLine where
mempty = zero
mappend = add
因为 totalQuantity 和 orderTotal 都是数字,所以它们在 (+)[=23= 下也形成一个幺半群] 有没有办法定义
add :: TotalLine -> TotalLine -> TotalLine
所以,我可以只在每个字段上传播 mappend 调用,而不必手动定义类似
的内容吗add line1 line2 =
TotalLine {
totalQuantity = totalQuantity line1 + totalQuantity line2,
orderTotal = orderTotal line1 + orderTotal line2
}
有 generic-deriving
个包裹完全符合您的要求:
{-# LANGUAGE DeriveGeneric #-}
import Generics.Deriving.Monoid
import GHC.Generics
data T = T {str :: String, str' :: String}
deriving (Generic, Show)
main = undefined
instance Monoid T where
mempty = memptydefault
mappend = mappenddefault
还有一些来自 ghci 的结果:
> T "a" "b" `mappend` T "c" "d"
< T {str = "ac", str' = "bd"}
但是对于您的 TotalLine
数据类型,它不是开箱即用的,因为 Int
和 Float
都没有 Monoid
的实例.
还添加一个依赖项只是为了这个目的不太经济。您最好手动实现 Monoid
实例。
关于为什么 GHC 不能派生 Monoid 实例已经some discussion,结果证明通常这样的派生实例可能不是唯一的。但是在数据类型只有的特殊情况下一个具有具体和幺半群字段的构造函数派生实例是唯一的。
请注意,有几个具有域 Int 的幺半群(Nat、Float、..)
所以我会发现阅读具有 instance Monoid Int
的代码非常混乱。然后 mappend
可以是加号、乘号、最大值、最小值等等中的任何一个。
如果你可以稍微改变一下类型(但它仍然与你的同构),你可以试试这个:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Monoid
newtype TotalLine = TotalLine (Sum Int, Sum Float) deriving Monoid