3

次のように定義されたモノイドがあるとしましょう。

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

instance Monoid TotalLine where
  mempty = zero
  mappend = add

totalQuantityとorderTotalは両方とも数値であるため、 (+)の下でモノイドも形成 します。定義する方法はありますか?

add :: TotalLine -> TotalLine -> TotalLine

そのため、次のようなものを手動で定義する代わりに、各フィールドでmappend呼び出しを伝播することはできますか?

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

3 に答える 3

7

ドメイン Int (Nat、Float、..) を持つモノイドがいくつかあることに注意してくださいinstance Monoid Int。次にmappend、プラス、タイムズ、最大、最小などのいずれかになります。

于 2016-03-18T15:37:45.793 に答える
4

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両方に.IntFloatMonoid

また、その目的のためだけに依存関係を追加するのはあまり経済的ではありません。Monoidインスタンスを手動で実装することをお勧めします。


GHC が Monoid インスタンスを派生できない理由についていくつかの議論がありましたが、一般に、そのような派生インスタンスは一意ではない可能性があることが判明しました。しかし、データ型が具象フィールドとモノイド フィールドを持つコンストラクターを 1 つしか持たない特殊なケースでは、派生インスタンスは一意です。

于 2016-03-18T15:36:08.153 に答える