そのようなtypeclassは何ですか


プログラミングでは、非常に頻繁に発生するパターンがあります.同じ型の2つのものをまとめて、その型の別のものを取得します.
a -> a -> a

その周波数を考えると、それにはいくつかの有用な抽象化があるでしょう.
そして、Haskellでは、我々はします.と呼ばれるタイプMonoid それは、「一緒にものを壊す」という概念に関する要約です.同じ名前の数学的構造からインスピレーションを引き出します.
この記事では、typeclassと構造の両方をカバーします.
記事の最後までに、
  • モノイドとは
  • 何がMonoid Haskellのtypeclass ;
  • 定義済みのモノイドインスタンスを使う方法Data.Monoid ;
  • あなた自身のインスタンスを定義する方法Monoid ;
  • モノイドはなぜ役に立つのか

  • 直観力の構築


    Monoidのような数学用語では、定義を読む前に例を見るのが常に良いです.
    したがって、Haskellでのモノイド様行動の3つの例を見てみましょう.
    最初のオフ、リスト++ (連結)演算子.
    Prelude> [1,2] ++ [3, 4] -- You can concatenate lists.
    [1,2,3,4]
    Prelude> [1,2] ++ [] -- Concatenating an empty element to a list doesn't change the result.
    [1,2]
    Prelude> [] ++ [1,2] 
    [1,2]
    Prelude> [1,2] ++ ([3,4] ++ [5,6]) -- It doesn't matter in which order you concatenate the lists, you get the same result either way.
    [1,2,3,4,5,6]
    Prelude> ([1,2] ++ [3,4]) ++ [5,6] 
    [1,2,3,4,5,6]
    
    
    その後、+ 演算子.
    Prelude> 1 + 2 -- You can sum two natural numbers together.
    3
    Prelude> 1 + 0 -- Adding a 0 doesn't change the sum.
    1
    Prelude> 0 + 1
    1
    Prelude> (1 + 2) + 3 -- It doesn't matter in which order you sum the numbers, you get the same result either way. 
    6
    Prelude> 1 + (2 + 3)
    6
    
    
    (代わりに、*演算子を使用した場合もあります.
    そして最後に、&& 演算子and ).
    Prelude> True && False -- You can join two booleans via &&. 
    False
    Prelude> a = False
    Prelude> a && True -- Adding && True doesn't impact the resulting boolean.
    False
    Prelude> True && a
    False
    Prelude> (True && True) && False -- It doesn't matter in which order you resolve the &&s, you get the same result either way.
    False
    Prelude> True && (True && False)
    False
    
    
    (あるいは、OR演算子を使ってブール演算を行いました.|| . その場合、結果を変更しない要素はFalse .)
    ご覧の通り、これら三つのことは同様に行動します.彼らは同じ法律に従っている.
    さて、これらの法則がどれほど正確かを見てみましょう.

    どのようなモノイドですか?


    数学では、モノイドは、その集合上の要素(数字やブールなど)の集合と二値演算からなる構造体である+ or && ).
    また、モノイドは以下の性質を満たす.

  • 「何もしない」というアイデンティティ要素がある.より正式な用語では、モノイドの要素セットから任意の要素Xを取得し、その要素と同一要素を持つモノイドのバイナリ操作を使用すると、同じ要素- x - backを取得します.例えば、1+0=1 , 2+0=0 など

  • 結合このプロパティは、方程式内の括弧を並べ替えることで方程式の結果を変更しないことを保証します.例えば、(1+2)+3=1+(2+3) .
  • Haskellにおけるモノイド


    どのように、モノイドはハスケルに見えますか?:info 刑事は事件である.🕵️‍♂️
    Prelude> :info Monoid
    type Monoid :: * -> Constraint
    class Semigroup a => Monoid a where
      mempty :: a
      mappend :: a -> a -> a
      mconcat :: [a] -> a
    
    
    ご覧の通り.Monoid Haskellでは、以下の3つのメソッドがあります.mempty , mappend , and mconcat .
  • mempty はバイナリ操作と一緒に使用した場合の結果に影響しない値です.言い換えれば、それは、モノイドのアイデンティティ要素です.
  • mappend (or <> ) は2つのモノイドを一緒に置く関数です.つまり、モノイドのバイナリ操作です.
  • mconcat 単体のリストを1つの値に減らす関数です.デフォルトではfoldr mappend mempty . ほとんどのデータ型に対しては良いことで、定義する必要はありませんmconcat インスタンスを定義するにはしかし、既定の実装が最適でないときには、関数の独自の実装を定義したい場合があります.
    オンノートmappend and <> .
  • typeclassは関数として定義されません<> , これはSemigroup , のスーパークラスMonoid 私が後で記事でカバーすること.すべての意図と目的のために、これらの機能は同じであるべきです.GHCの将来のリリースではmappend will be removed , それで、あなたは使用を勧められます<> .

    定義済みのモノイドインスタンスの使い方


    前の例からデータ型でこれらのモノイドメソッドを使用してみましょう.
    リストで動作します.
    Prelude> [1,2] <> [3,4]
    [1,2,3,4]
    
    Prelude> mempty :: [a]
    []
    
    Prelude> [1,2] <> mempty
    [1,2]
    
    
    しかし、あなたがしようとするならば1 <> 3 , GHCIでエラーが発生します.
    <interactive>:1:1: error:
        • Ambiguous type variable 'a0' arising from a use of 'print' 
    ...
    🤔
    
    
    これは1つのインスタンスがないからですMonoid を参照してください.
    あなたが選択したバイナリ操作に応じて合計モノイド、製品のモノイド、および多くを持つことができます.GHCはどの操作を使いたいかわからない.
    そのため、データ型をラップし、それらの型を使用するコンテキストに従って、モノイドインスタンスを作成する必要があります.Data.Monoid このようなラッパータイプを定義しますSum , Product , など
    newtype Sum a = Sum { getSum :: a }
    
    
    彼らがどのように働くか見ましょう.
    Prelude> import Data.Monoid
    Prelude Data.Monoid> Sum 1 <> Sum 3
    Sum {getSum = 4}
    
    Prelude Data.Monoid> Product 2 <> Product 5
    Product {getProduct = 10}
    
    
    同様に、BooleansはAll and Any それらのために定義されたモノイド.
    Prelude Data.Monoid> All True <> All False
    All {getAll = False}
    Prelude Data.Monoid> Any True <> Any False
    Any {getAny = True}
    
    
    使えますmconcat これらのモノイドのリストをまとめる.
    result = mconcat [Sum 4, Sum 6, Sum 8, mempty]
    
    
    そして、アンラップされた結果を得るには、便利に呼ばれるレコード名を使用して、それらをアンラップすることができますgetX .
    Prelude Data.Monoid> getSum result
    18
    
    

    Haskellでモノイドインスタンスを作成する方法


    Haskellで独自のモノイドインスタンスを作成してみましょう.
    まず、カスタムデータ型を作成しますMove これはロボットが2次元場で動くよう指示する.
    data Move = Move Int Int deriving (Show, Eq)
    
    
    データ型のモノイドインスタンスを作成するには、まず Semigroup それのインスタンスSemigroup のスーパークラスMonoid ( GHC 8.4以降).
    Prelude> :info Monoid
    type Monoid :: * -> Constraint
    class Semigroup a => Monoid a where
    ... 
    
    Prelude> :info Semigroup
    type Semigroup :: * -> Constraint
    class Semigroup a where
      (<>) :: a -> a -> a
    
    
    しかし、心配しないでください、ここに新しい何もありません.Aを作るSemigroup インスタンスは、定義の丸い方法ですmappend .
    半群がアイデンティティ要素のないモノイドであるので、これはそうですmempty ). これは1つのメソッドを定義します.<> – と同じmappend , つの値を組み合わせるためのバイナリ演算.
    では、次のインスタンスを定義しましょうSemigroup . つの動きを追加するにはx and y 値.
    instance Semigroup Move where
      Move x1 y1 <> Move x2 y2 = Move (x1 + x2) (y1 + y2)
    
    
    その後、我々は定義することができますMonoid インスタンス.インスタンスを定義するには、mempty だってmappend<> .
    The mempty それは我々の場合、どこにも動かないことを意味します.Move 0 0 .
    instance Monoid Move where
      mempty = Move 0 0
    
    
    注:あなたのモノイドのインスタンスを作成しながら、モノイドの法則に従うように注意する必要があります.ハスケルproperty-based tests ) 私たちのモノイドのインスタンスが意味を確認する方法はありません.例えば、私たちは定義できましたmempty あるMove 0 (-1) , これはいくつかの奇妙な動作につながるでしょう.
    それは我々が必要とするすべてですMove 一人称!🎉
    今、我々はGHCIでそれを再生することができます.
    *Main> Move 3 4 <> Move 8 9
    Move 11 13
    *Main> Move 3 4 <> mempty
    Move 3 4
    
    
    また、mconcat 移動リストを折り畳む方法.
    *Main> stay = mempty :: Move
    *Main> moves = [Move 1 2, Move (-3) 5, Move (-6) 3, stay, Move 2 3]
    *Main> mconcat moves
    Move (-6) 13
    
    

    なぜモノイドが必要ですか?


    一般的に、モノイドは非常に高度な、興味深い、またはクールではありません.
    しかし、彼らは本当に便利で、非常に簡単です.<> は、多くの異なるタイプを連結するのに使用されて、基本的なビルディングブロックと考えられることができました.それはあなたがすべてのHaskellプロジェクトで会うという演算子です.
    あなたが現実のユースケースを捜しているならば、下記の更なる学習セクションはチャットフィルタを作って、選挙投票分布を計算するために単体の使用をカバーする資源を持ちます.

    更なる学習


    これは、クイック入門入門ですMonoid Haskellのtypeclassうまくいけば、今、どのようなモノイドの法則は、どのようにHaskellでモノイドを使用する方法を定義し、どのようにMonoid typeclass
    参考になるかもしれませんが、

  • 私は、絶対的にHaskellについてTsodingのビデオを好みます.チャットのメッセージのフィルタを実装しながら、この1つで、彼はどのようにモノイドが役に立つことができるかを示しています.

  • Electoral vote distributions are monoids . ここでは、モノ世界が現実世界の問題を解決するために使用できる方法の別の例です.

  • Monoids in Haskell . 私はトピックで見つけることができる最高の紹介記事.
  • あなたがHaskellについてより初心者指向の記事を読むことを望むならば、あなたは我々の会報(下記のフォームによって)を購読するために、または、我々について来て歓迎です.

    演習

  • ラッパータイプを実装するexclusive OR (XOR) . それの半群とモノイドのインスタンスを作成します.
  • ラッパータイプを実装するlogical biconditional (XNOR) . それの半群とモノイドのインスタンスを作成します.
  • インスタンスは1で作成します.と2 .モノイド法に続いてください?なぜ?
  • ご存知かもしれませんが、半群はアイデンティティ要素のないモノイドです.半群であるが、モノイドではない構造の例を考え出せますか?