La definizione minima di programmatore di una monade

6

Sto cercando di formulare una definizione di monade senza bisogno di termini matematici o Haskell per capire.

Si può pensare a una monade come a una funzione che accetta un valore e lo avvolge in modo tale da soddisfare specifiche interfacce e vincoli comportamentali che si sono rivelati utili quando si lavora in uno stile funzionale?

I vincoli di interfaccia sono:

i. Ha un costruttore di tipi che ne definisce il tipo ( Che cos'è questo? ).

II. Ha una funzione unitaria che converte un valore nel corrispondente tipo monadico.

III. Ha un metodo "bind" che accetta una monade, una funzione che accetta un certo tipo e restituisce una monade ( è questa un'altra monade? ), e restituisce una monade.

I vincoli comportamentali sono:

i. Identità di sinistra

Monad(x).bind(fn) == Monad(fn(x)); // for all x, fn

II. Identità corretta

Monad(x).bind(function(x){return x;}) == Monad(x); // for all x

III. Associatività

Monad(x).bind(fn1).bind(fn2) == Monad(x).bind(function(x) {
  return fn2(fn1(x));
});

Questa è una definizione minima di una monade?

    
posta Ben 05.07.2016 - 16:18
fonte

4 risposte

10

La risposta di Mason è corretta, e sì, dovresti leggere la mia serie. Per enfatizzare il suo punto in modo più approfondito:

Can a monad be thought of as a function that accepts a value and wraps it such that it meets specific interface and behavioral constraints

, ma questo non è il modo migliore per caratterizzare una monade. Tu sei molto vicino però; possiamo apportare piccole modifiche alla formulazione e arrivare a una migliore caratterizzazione.

Dici una monade, chiamala M , è una funzione che accetta un valore e produce un valore avvolto. È è che è problematico. Piuttosto, un monad ha una tale funzione. Un monad M è una raccolta di tre cose:

  • Una trasformazione che accetta un tipo e produce un nuovo tipo. In C # chiamiamo tale trasformazione un "tipo generico". Abbiamo un tipo generico M<T> , abbiamo un tipo int e produciamo un nuovo tipo M<int> .

  • Una funzione generica unit che accetta un valore di tipo T e produce un valore di tipo M<T> .

  • Una funzione generica bind che accetta un valore di tipo M<T> e una funzione da T a M<U> e produce un M<U> .

Questa seconda cosa è la tua "funzione che accetta un valore e lo avvolge". Non è che un monad è quella funzione; una monade è la combinazione del costruttore di tipo monadico stesso, del wrapper e della funzione che lega una nuova funzione alla fine di un flusso di lavoro monadico.

Questo è il motivo per cui nella teoria delle categorie le monadi sono talvolta chiamate "triple"; perché hai bisogno di tre cose per caratterizzare una monade.

Ora, noterai che faccio la stessa cosa di te; nella mia serie di articoli caratterizzo una monade come un tipo generico che obbedisce a certe regole ; cioè, dico che il monad è la prima cosa, e che la prima cosa deve avere essa stessa la seconda e la terza cosa.

Come esattamente caratterizziamo le relazioni tra le parti non ha molta importanza; ciò che conta è che ci debbano essere queste tre cose: un modo per "amplificare" i tipi, un modo per "avvolgere" i valori e un modo per trasformare un'istanza di una monade in un'altra "legando" una funzione su di essa. Se hai queste tre cose e obbediscono alle regole ovvie di identità, transitività e così via, allora hai una monade.

    
risposta data 08.07.2016 - 17:42
fonte
6

Eric Lippert ha scritto una grande serie sulle monadi che in realtà le spiega in un modo che ha senso per i non Haskellers. Vale la pena leggere tutto, ma l'idea di base è la seguente:

Una monade è un "potenziatore di tipo" che prende un tipo di base e fa qualcosa di nuovo (come trasformare un tipo T in una sequenza come IEnumerable<T> ,) con le seguenti caratteristiche:

A monad is a generic type M<T> such that:

  • There is some sort of construction mechanism that takes a T and returns an M<T>. We’ve been characterizing this as a method with signature

    static M<T> CreateSimpleM<T>(T t)

  • Also there is some way of applying a function that takes the underlying type to a monad of that type. We’ve been characterizing this as a method with signature:

static M<R> ApplySpecialFunction<A, R>(M<A> monad, Func<A, M<R>> function)

Finally, both these methods must obey the monad laws, which are:

  • Applying the construction function to a given instance of the monad produces a logically identical instance of the monad.
  • Applying a function to the result of the construction function on a value, and applying that function to the value directly, produces two logically identical instances of the monad.
  • Applying to a value a first function followed by applying to the result a second function, and applying to the original value a third function that is the composition of the first and second functions, produces two logically identical instances of the monad.

Se questa definizione sembra un po 'confusa, il prossimo paragrafo spiega perché:

Whew! And now perhaps you see why I started this series all those weeks ago with the idea of exploring the pattern by looking at examples, rather than starting in with the monad laws.

Se inizi a il primo post e leggi la serie, il concetto dovrebbe in realtà ha senso alla fine. Non c'è "una monade è come un hot dog" senza senso qui, per fortuna!

    
risposta data 05.07.2016 - 17:23
fonte
2

i) è una funzione che accetta un tipo e restituisce un nuovo tipo, vale a dire un tipo generico, non sono sicuro che avrebbe un utilizzo diretto in js poiché non hai tipi

iii) restituirebbe un tipo diverso, ma nella stessa monade, è possibile riproiettare da m a - > m b

è una definizione minima, tuttavia di solito ci sono altre funzioni che si definiscono ad es. ogni monade è un funtore in modo da poter sempre definire fmap per la tua monade e spesso hai anche una funzione join / flatten (il bind può essere implementato in termini di fmap e join)

    
risposta data 05.07.2016 - 16:31
fonte
1

Can a monad be thought of as a function that accepts a value and wraps it such that it meets specific interface and behavioral constraints that have been found to be useful when working in a functional style?

No. La funzione che racchiude un valore è un'unità.

Se stai cercando di capire se ha senso spiegare le monadi come una funzione unitaria che restituisce un oggetto con un metodo di bind che segue le leggi monad, non funziona del tutto. Il problema è che ci sono valori monadici che non possono essere creati con la funzione dell'unità.

Ad esempio, nella monade Maybe, il valore Nothing non può essere creato con l'unità e l'intero punto dell'esistenza della monade Maybe è di consentire il valore Nothing.

In generale, i valori monadici creati dalla funzione di unità sono semplici, noiosi e chiari, e non illustrano il motivo per cui volevamo avere la monade con cui abbiamo a che fare in primo luogo. L'unità è ideale per trasformare valori semplici in valori monadici e funzioni semplici in funzioni monadiche per la compatibilità, ma il gioco è fatto.

Dopo averci pensato un po ', sono stato in grado di elaborare una prova su carta che tutte le monadi utili hanno valori monadici che non possono essere creati dall'unità. (Specificamente, o c'è solo un valore monadico nella monade (che è inutile), o la monade è isomorfa alla monade dell'identità (che è inutile nello stesso modo in cui la funzione di identità è inutile), o la monade ha valori monadici che non può essere creato dall'unità.)

Questo è sbagliato

Monad(x).bind(function(x){return x;}) == Monad(x); // for all x

dovrebbe essere

unit(x) == function(x){return Monad(x);} // I'm assuming this is what you mean by Monad(x)
Mx.bind(unit) == Mx; // for all monadic values Mx

Questo

Monad(x).bind(fn) == Monad(fn(x)); // for all x, fn

dovrebbe essere

Monad(x).bind(fn) == fn(x); // for all values x and monadic functions fn

È possibile eseguire il binding con qualsiasi funzione monadica, che è una funzione di un argomento che restituisce un valore monadico dello stesso tipo su cui si basa l'implementazione di bind, ma non è possibile associare tutte le funzioni.

Questo è sbagliato

Monad(x).bind(fn1).bind(fn2) == Monad(x).bind(function(x) {
  return fn2(fn1(x));
});

dovrebbe essere questo

// for any monadic value Mx and any 2 monadic functions fn1 and fn2 whose types line up
Mx.bind(fn1).bind(fn2) == Mx.bind(function(x) {
  return fn1(x).bind(fn2);
});

iii. It has a "bind" method that takes a monad, a function that takes a some type and returns a monad (is this another monad?), and returns a monad.

Stai usando la parola monad per indicare diverse cose, che penso sia soddisfacente, ma è potenzialmente poco chiaro per le persone che non hanno ancora messo le loro teste in giro per le monadi. Ci sono tre cose che potresti significare con la monade: il modello generale delle monadi / monadi in generale, una monade specifica o un valore monadico. Le Monade in generale sono ciò che stai cercando di definire / spiegare, una monade specifica sarebbe una particolare istanza di questo schema / interfaccia generale (come la monade Forse o la monade Lista), e un valore monadico è un valore del tipo che output unit o bind (come la lista [1,2,3] per la lista monad).

Quindi possiamo semplificarlo a

iii. It has a "bind" method that takes a monadic value and a monadic function and returns a monadic value.

Sebbene ciò non chiarisca che il bind non funziona tra diverse monadi o che il tipo di output della funzione monadica è uguale al tipo di output del bind.

Un altro modo di guardare il legame è come un equivalente monadico dell'applicazione di funzione. L'applicazione di funzione normale assume un valore normale e una funzione semplice e restituisce un valore normale. Il legame monadico assume un valore monadico e una funzione monadica e restituisce un valore monadico. Se hai un valore monadico Mx e una funzione monadica fn , non puoi fare fn(Mx) , perché fn non funziona su valori monadici. Ma puoi fare Mx.bind(fn) .

i. It has a type constructor that defines its type (What is this?).

Un costruttore di tipi è un concetto che esiste in Haskell, ma non in javascript. Non sono sicuro del modo migliore per parlare di questo in javascript, ma probabilmente finirei a parlare di Classi, perché anche se non esistono realmente in javascript, i programmatori javascript sanno qual è il concetto. Per qualsiasi monade, ci deve essere una definizione di cosa significa valore monadico per quella particolare monade, ed è quello che va qui.

    
risposta data 06.07.2016 - 01:45
fonte

Leggi altre domande sui tag