8

だから、私は現在Haskellを学んでおり、モノイドの理解を確認したり、暴言を吐いたりしたいと思います。

CIS194コースを読んでわかったことは、モノイドは基本的に、カスタム セットでカスタム バイナリ操作を定義するための「API」であるということです。

私が自分自身にもう少し知らせに行ったよりも、物事を明確にしようとする非常に紛らわしい大量のチュートリアルに出くわしたので、もうよくわかりません.

私はまともな数学的背景を持っていますが、すべての比喩から混乱してしまい、モノイドの理解に対する明確なイエス/ノーの答えを探しています.

4

3 に答える 3

8

ウィキペディアから

数学の一分野である抽象代数では、モノイドは単一の連想二項演算と単位要素を持つ代数構造です。

あなたの理解は正しいと思います。プログラミングの観点から見ると、Monoid は、実装する必要がある 2 つの「メソッド」を持つインターフェイスです。

あなたの説明に欠けていると思われる唯一の部分は、あなたがセミグループを説明している「アイデンティティ」です

「ゼロ」または「空」を持ち、2 つの値を組み合わせる方法があるものはすべてモノイドになることができます。注意すべきことの 1 つは、set/type が複数の方法でモノイドになる可能性があることです。たとえば、additionwith identity0multiplicationwith identityを介した数値など1です。

于 2015-09-02T17:34:53.960 に答える
5

ウルフラムから:

モノイドは、連想二項演算で閉じられた集合であり、S 内のすべての a に対して Ia=aI=a となる恒等元 I を S 内に持ちます。

ウィキから:

数学の一分野である抽象代数では、モノイドは単一の連想二項演算と単位要素を持つ代数構造です。

したがって、あなたの直感は多かれ少なかれ正しいです。

Haskell の「カスタム セット」ではなく、タイプに対して定義されていることに注意してください。違いはわずかですが (型理論の型は集合論の集合と非常に似ているため)、Monoid インスタンスを定義できる型は、数学的な集合を表す型である必要はありません。

つまり、タイプは、そのタイプのすべての値のセットを記述します。モノイドは「インターフェース」であり、そのインターフェースに準拠すると主張する型は、その型の 2 つの値を結合する 2 項演算である ID 値を提供する必要があり、すべての一般的なモノイド演算が意図したとおりに機能し (モノイド値のリストの一般的な合計など)、非論理的/矛盾した結果を生成しません。

また、型が Monoid クラスのインスタンスであるためには、そのセット (型) に ID 要素が存在する必要があることに注意してください。

たとえば、自然数は両方の加算 (identity = 0)の下でモノイドを形成します。

0 + n = n
n + 0 = n

乗算と同様に (identity = 1):

1 * n = n
n * 1 = n

++また、リストは(identity = [])の下でモノイドを形成します。

[] ++ xs = xs
xs ++ [] = xs

また、型の関数はa -> a構成下でモノイドを形成します (identity = id)

id . f = f
f . id = f

そのため、モノイドはセットを表す型ではなく、セットとして見たときの型に関するものであることに留意することが重要です。


不正に構築されたモノイド インスタンスの例として、次のことを考慮してください。

import Data.Monoid

newtype MyInt = MyInt Int deriving Show

instance Monoid MyInt where
  mempty = MyInt 0
  mappend (MyInt a) (MyInt b) = MyInt (a * b)

mconcatここで値のリストを取得しようとすると、ID 値と 2 項演算がうまく連携しないため、MyInt常に結果が得られます。MyInt 00*

λ> mconcat [MyInt 1, MyInt 2]
MyInt 0
于 2015-09-02T17:40:09.713 に答える
3

基本的なレベルでは、その通りです。これは、 で表す二項演算子の単なる API です<>

ただし、モノイドの概念の価値は、他の型やクラスとの関係にあります。文化的に、これ<>が同じタイプの 2 つのものを一緒に結合/追加する自然な方法であると判断しました。

次の例を検討してください。

{-# LANGUAGE OverloadedStrings #-}

import Data.Monoid

greet x = "Hello, " <> x

この関数greetは非常に多態的ですx。いくつかの可能性を挙げると、String、ByteString、または Text のいずれかになります。さらに、これらのケースのそれぞれで、基本的に期待どおりのことを行います -x文字列 `"Hello, " に追加します。

さらに、蓄積できるものなら何でも動作するアルゴリズムがたくさんあり、それらはモノイドへの一般化の良い候補です。たとえば、クラスのfoldMap関数を考えてみましょう:Foldable

foldMap ::  Monoid m => (a -> m) -> t a -> m

foldMap構造体を折り畳むという考え方を一般化するだけでなく、適切なモノイド インスタンスを代入することで累積がどのように実行されるかを一般化できます。

Int を含む折り畳み可能な構造がある場合、モノイドをt使用foldMapしてInt の合計を取得したり、積を取得したりできます。SumProduct

最後に、使用する<>と便利になります。たとえば、さまざまな Set の実装が豊富にありますが、それらのすべてs <> tは常に 2 つのセットsand t(同じ型) の和集合です。これにより、セットの基になる実装に依存しないコードを記述できるため、コードが簡素化されます。シーケンス、ツリー、マップ、プライオリティ キューなど、他の多くのデータ構造についても同じことが言えます。

于 2015-09-02T17:52:24.820 に答える