2013-03-31 5 views
49

Ich bin sehr verwirrt mit diesen drei Konzepten.Einfache Beispiele zur Veranschaulichung von Kategorie, Monoid und Monad?

Gibt es einfache Beispiele zur Veranschaulichung der Unterschiede zwischen Kategorie, Monoid und Monad?

Es wäre sehr hilfreich, wenn es eine Illustration dieser abstrakten Konzepte gibt.

+12

Haben Sie das gelesen [Typeclassopedia] (http://www.haskell.org/haskellwiki/Typeclassopedia)? – dave4420

+0

Vielen Dank für Ihren Rat. Ich hätte es zuerst lesen sollen. – Znatz

+1

[Monaden sind wie Burritos] (http://blog.plover.com/prog/burritos.html). Ja wirklich. –

Antwort

91

Dies ist wahrscheinlich nicht die Antwort, die Sie suchen, aber hier geht es sowieso:

Ein wirklich krumme Weg bei Monaden suchen & co.

Eine Möglichkeit, abstrakte Konzepte wie diese zu betrachten, besteht darin, sie mit grundlegenden Konzepten wie gewöhnlichen Listenverarbeitungsoperationen zu verknüpfen. Dann könnten Sie das sagen,

  • Eine Kategorie verallgemeinert die (.) Operation.
  • Ein Monoid verallgemeinert die (++) Operation.
  • Ein Funktor verallgemeinert die map Operation.
  • Ein anwendbarer Funktor verallgemeinert die zip (oder zipWith) Operation.
  • Eine Monade verallgemeinert die concat Operation.

A Kategorie

Eine Kategorie von einem Satz (oder einer Klasse) von Objekten und Bündel von Pfeilen besteht, die jeweils zwei der Objekte verbinden. Außerdem sollte für jedes Objekt ein Identitätspfeil vorhanden sein, der dieses Objekt mit sich selbst verbindet. Wenn es einen Pfeil (f) gibt, der auf einem Objekt endet, und einen anderen (g), der von demselben Objekt aus beginnt, sollte es außerdem einen zusammengesetzten Pfeil mit der Bezeichnung g . f geben.

In Haskell wird dies als eine Typklasse modelliert, die die Kategorie der Haskell-Typen als Objekte darstellt.

class Category cat where 
    id :: cat a a 
    (.) :: cat b c -> cat a b -> cat a c 

Grundlegende Beispiele für eine Kategorie sind Funktionen. Jede Funktion verbindet zwei Typen, für alle Typen gibt es die Funktion id :: a -> a, die den Typ (und den Wert) mit sich selbst verbindet. Die Zusammensetzung der Funktionen ist die gewöhnliche Funktionszusammensetzung.

Kurz gesagt, Kategorien in Haskell Basis sind Dinge, die verhalten sich wie Funktionen, d. H. Sie können nacheinander mit einer verallgemeinerten Version von (.) setzen.

A Monoid

monoid A ist eine Gruppe mit einem Einheitselement und einem assoziativen Betrieb. Dies ist ein Modell in Haskell als:

class Monoid a where 
    mempty :: a 
    mappend :: a -> a -> a 

Gängige Beispiele für Monoide umfassen:

  • Menge der ganzen Zahlen, das Element 0, und die Operation (+).
  • Satz positiver Ganzzahlen, das Element 1 und die Operation (*).
  • Set aller Listen, die leere Liste [] und die Operation (++). Diese

modelliert in Haskell als

newtype Sum a = Sum {getSum :: a} 
instance (Num a) => Monoid (Sum a) where 
    mempty = Sum 0 
    mappend (Sum a) (Sum b) = Sum (a + b) 

instance Monoid [a] where 
    mempty = [] 
    mappend = (++) 

Monoide verwendet werden, um 'verbinden' und akkumulieren Dinge. Zum Beispiel kann die Funktion mconcat :: Monoid a => [a] -> a verwendet werden, um eine Liste von Summen auf einzelne Summe oder eine verschachtelte Liste in eine flache Liste zu reduzieren. Betrachten Sie dies als eine Art Verallgemeinerung von (++) oder (+) Operationen, die auf eine Art zwei Dinge "verschmelzen".

A Functor

Ein Funktor in Haskell ist eine Sache, die ganz direkt den Betrieb verallgemeinert map :: (a->b) -> [a] -> [b]. Anstatt über eine Liste zu mappen, bildet sie über Struktur, wie eine Liste, Binärbaum oder sogar eine IO-Operation. Functors werden wie folgt modelliert:

class Functor f where 
    fmap :: (a->b) -> f a -> f b 

Kontrast diese auf die Definition der normalen map Funktion.

Ein Applicative Functor

Applicative functors können mit einem generalisierten zipWith Betrieb wie die Dinge zu sehen. Funktoren ordnen sich zu einem bestimmten Zeitpunkt über allgemeine Strukturen hinweg, aber mit einem Applicative-Funktor können Sie zwei oder mehr Strukturen zusammenfügen. Für die einfachste Beispiel können Sie applicatives zip zusammen zwei ganzen Zahlen innerhalb des Maybe-Typ:

pure (+) <*> Just 1 <*> Just 2 -- gives Just 3 

Beachten Sie, dass die Struktur das Ergebnis zum Beispiel beeinflussen können:

pure (+) <*> Nothing <*> Just 2 -- gives Nothing 

Kontrast dieser den üblichen zipWith Funktion:

zipWith (+) [1] [2] 

Statt nur Listen, die applicative Werke für alle Arten von Strukturen. Darüber hinaus verallgemeinert der clevere Trick mit pure und (<*>) das Zippen, um mit einer beliebigen Anzahl von Argumenten zu arbeiten. Um zu sehen, wie dies funktioniert, überprüfen Sie die folgenden Arten, während das Konzept der teilweise angewendet Funktionen zur Hand zu halten:

instance (Functor f) => Applicative f where 
    pure :: a -> f a 
    (<*>) :: f (a -> b) -> f a -> f b 

Beachten Sie auch die Ähnlichkeit zwischen fmap und (<*>).

A Monad

Monads werden häufig verwendet, verschiedene Rechen Kontexten, wie nicht-deterministisch, oder Seiteneffekt Berechnungen zu modellieren. Da es schon viel zu viele Monad Tutorials gibt, empfehle ich einfach The best one, anstatt noch einen zu schreiben.

In Bezug auf die normalen Listenverarbeitungsfunktionen verallgemeinern Monaden die Funktion concat :: [[a]] -> [a], um mit vielen anderen Arten von Strukturen neben Listen zu arbeiten.Als ein einfaches Beispiel, die monadische Operation join kann abflachen verschachtelte Maybe Werte verwendet werden:

join (Just (Just 42)) -- gives Just 42 
join (Just (Nothing)) -- gives Nothing 

Wie dies auf die Verwendung von Monaden als Mittel zur Strukturierung Berechnungen verwendet ist? Betrachten Sie ein Spielzeugbeispiel, bei dem Sie zwei aufeinanderfolgende Abfragen aus einer Datenbank ausführen. Die erste Abfrage gibt Ihnen einen Schlüsselwert zurück, mit dem Sie eine weitere Suche durchführen möchten. Das Problem hierbei ist, dass der erste Wert in Maybe eingeschlossen ist, so dass Sie nicht direkt damit abfragen können. Statt dessen, wie es vielleicht ein Functor ist, könnten Sie stattdessen den Rückgabewert mit der neuen Abfrage fmap. Dies würde Ihnen zwei verschachtelte Maybe Werte wie oben geben. Eine andere Abfrage würde zu drei Schichten von Maybe s führen. Dies wäre ziemlich schwierig zu programmieren, aber ein monadischer join gibt Ihnen eine Möglichkeit, diese Struktur zu glätten, und arbeiten mit nur einer einzigen Ebene von Maybe s.

(ich glaube, ich werde diesen Posten Bearbeitung viel, bevor es überhaupt Sinn macht ..)

+1

+1. Oh, und 'concat :: [[a]] -> [a]'. – phg

+0

'mempty = 0' sollte' mempty = Summe 0' sein. – snak

+5

Ich mag diese Antwort, aber Sie möchten vielleicht darauf hinweisen, dass die Standard 'Applicative' -Instanz für' [] 'nicht die Zippy ist, sondern das kartesische Produkt. Die nicht sehr nützliche zippy list monad ist nur auf Listen mit konsistenter Länge gültig und ihr 'Join' nimmt die Diagonale. –

Verwandte Themen