Haskell 单倍体映射的自动传播

Haskell 单倍体映射的自动传播,haskell,monoids,Haskell,Monoids,假设我有一个定义如下的幺半群: data TotalLine = TotalLine { totalQuantity :: Int, orderTotal :: Float } instance Monoid TotalLine where mempty = zero mappend = add 由于totalQuantity和orderTotal都是数字,它们也在(+)下形成一个幺半群 有什么办法来定义吗 add :: TotalLine -> TotalLine ->

假设我有一个定义如下的幺半群:

data TotalLine = TotalLine { totalQuantity :: Int, orderTotal :: Float }

instance Monoid TotalLine where
  mempty = zero
  mappend = add
由于totalQuantityorderTotal都是数字,它们也在(+)下形成一个幺半群 有什么办法来定义吗

add :: TotalLine -> TotalLine -> TotalLine
因此,我是否可以在每个字段上传播mappend调用,而不必手动定义如下内容

add line1 line2 =
  TotalLine {
    totalQuantity = totalQuantity line1 + totalQuantity line2,
    orderTotal = orderTotal line1 + orderTotal line2
   }

通用派生
包完全符合您的要求:

{-# 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"}
>T“a”“b”`mappend`T“c”“d”
但是对于
totaline
数据类型,它不能开箱即用,因为
Int
Float
都没有
Monoid
的实例

另外,仅仅为了这个目的而添加依赖项并不那么经济。您最好手动实现
Monoid
实例



关于GHC不能派生幺半群实例的原因一直存在争议,结果证明,一般来说,这种派生实例可能不是唯一的。但在特殊情况下,当数据类型只有一个构造函数具有具体字段和幺半体字段时,派生实例是唯一的。

注意,有几个幺半体具有域Int(Nat、Float,…)
因此,我会发现读取具有
实例幺半群Int
的代码非常混乱。然后
mappend
可以是加号、倍、最大值、最小值和更多值中的任意一个。

如果您可以稍微更改类型(但仍然与您的类型相同),您可以尝试以下方法:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Monoid

newtype TotalLine = TotalLine (Sum Int, Sum Float) deriving Monoid

小调:我一开始被括号弄糊涂了,因为我误读了它,以为它暗示了Nat,Float,。。。“但是在特殊情况下,当数据类型只有一个具有具体字段和幺半体字段的构造函数时,派生实例是唯一的。”虽然有一个自然幺半体,但它仍然不是唯一的。它可以
mappend
某些字段的顺序相反。