0

次のデータ型とセミグループ インスタンスがあります。

data Or a b =
  Fst a
  | Snd b deriving (Eq, Show)

instance Semigroup (Or a b) where
  (<>) (Fst a) (Fst b) = Fst b
  (<>) (Snd a) (Fst b) = Snd a
  (<>) (Fst a) (Snd b) = Snd b
  (<>) (Snd a) (Snd b) = Snd a

上記の型のモノイド インスタンスを作成したいのですが、その方法がわかりません。次の定義を使用する場合

instance (Monoid a, Monoid b) => Monoid (Or a b) where
  mempty = (Fst mempty)
  mappend = (<>)

への入力のすべてのペアで機能しますが<>、私がいるものを除きます。mappend

(Fst a) <> mempty

に評価されmemptyます。

memptyが有効になるようにこれを修正するにはどうすればよいですか? memptyが左か右かによって決まるため、新しい構文や概念がないとできないようです...

4

1 に答える 1

7

常に最初の引数をとる完全に優れた (そしてより単純な) 半群があります。

newtype FirstS a = FirstS a
instance Semigroup (FirstS a) where
    a <> b = a

残念ながら、ラップされた型の些細な選択を除いて、この操作の左単位がないため、これはモノイドではありません。標準タイプは、次のように識別 ID 要素を追加することでFirstパッチを適用します。FirstS

newtype First a = First (Maybe a)
instance Semigroup (First a) where
    First Nothing <> b = b
    a <> First Nothing = a
    a <> b = a -- this clause is exactly as before

Monoid次に、 を選択してインスタンスを簡単に作成できますmempty = First Nothing。タイプに識別 ID 要素を追加することで、同様のトリックを引き出すことができます。

data Or a b = Fst a | Snd b | Neither
instance Semigroup (Or a b) where
    Neither <> b = b
    a <> Neither = a
    -- the remainder of the clauses are as before

これにより、mempty = Neither非常に簡単に選択できます。

このパターンは非常に頻繁に役立つため、実際には に newtype ラッパーが含まれsemigroupsているため、元の型を使用してこのパッチを適用した型をOr a b単純に記述し、とインスタンスを無料Option (Or a b)で取得することもできます。SemigroupMonoid

于 2016-03-08T20:44:39.567 に答える