2012-01-09 7 views
11

ho letto un article che diceva:Quale funzionalità si ottiene gratuitamente con Functors o altre classi di tipi?

Fornire le istanze per i molti tipo-classi standard [Funtori] immediatamente vi darà un sacco di funzionalità per praticamente esenti

La mia domanda è: qual è questa funzionalità che si ottiene gratuitamente (per funtori o altre classi di tipi)? So qual è la definizione di un functor, ma cosa ottengo per libero definendo qualcosa come un functor/altra classe di tipo. Qualcosa di diverso da una sintassi più carina. Idealmente questo sarebbe funzioni generali e utili che operano su funtori/altre classi di tipi.

La mia immaginazione (potrebbe essere sbagliato) di ciò che significa libero è le funzioni di questo tipo: TypeClass x => useful x y = ..

== Modifica/Additition ==

Credo di essere principalmente chiedendo il più astratto (e cervello incredibile) classi di tipo, come quelli in this image. Per le classi meno astratte come Ord, la mia intuizione orientata agli oggetti comprende.

risposta

9

I funzionali sono semplici e probabilmente non l'esempio migliore. Diamo un'occhiata a Monadi invece:

  • liftM - se qualcosa è una monade, ma è anche un Functor dove liftM è fmap.
  • >=>, <=<: è possibile comporre le funzioni a -> m b gratuitamente dove m è la tua monade.
  • foldM, mapM, filterM ... si ottengono alcune funzioni di utilità che generalizzano le funzioni esistenti per utilizzare la monade.
  • when, guard * e unless - si ottengono anche alcune funzioni di controllo gratuitamente.
  • join - questo è in realtà abbastanza fondamentale per la definizione di una monade, ma non è necessario definirlo in Haskell poiché è stato definito >>=.
  • trasformatori - ErrorT e roba. È possibile bloccare la gestione degli errori sul nuovo tipo, gratuitamente (dare o prendere)!

Fondamentalmente, si ottiene una vasta gamma di funzioni standard "sollevate" per utilizzare il nuovo tipo non appena si crea un'istanza Monad. Diventa anche banale (ma purtroppo non automatico) per renderlo un Functor e Applicative pure.

Tuttavia, questi sono tutti "sintomi" di un'idea più generale. Puoi scrivere codice interessante, non banale che si applica a tutte le monadi. Potresti trovare alcune delle funzioni che hai scritto per il tuo tipo - che sono utili nel tuo caso particolare, per qualsiasi motivo - possono essere generalizzate a tutte le monadi. Ora si può prendere improvvisamente la vostra funzione e usarlo su parser ed elenchi, e maybes e ...

* Come Daniel Fischer utilmente sottolineato, guard richiede MonadPlus piuttosto che Monad.

+5

'guardia' richiede' MonadPlus'. –

+0

@DanielFischer: Oops. Buon punto –

+0

Dal momento che sembra esserci una manciata di tali funzioni di libreria, anche per Monade che è una classe di caratteri piuttosto ricca, direi che è improbabile che accada. È _eticamente possibile che il tuo codice possa magicamente generalizzare a tutte le monadi, ma praticamente se esistessero, vedrei molte più funzioni utili gratuitamente per le monadi. – user1138184

4

Ci sono molte delle funzioni standard in haskell che richiedono che i loro argomenti implementino una o più classi di tipi. Farlo nel tuo codice consente ad altri sviluppatori (o a te stesso) di utilizzare i tuoi dati in modi che già conoscono, senza dover scrivere funzioni aggiuntive.

Ad esempio, l'implementazione della classe di tipo Ord consente di utilizzare elementi come ordinamento, min, max, ecc. In caso contrario, occorrerebbe ordinare ordinamento e simili.

4

Sì, significa che l'implementazione della classe di tipo Foo offre tutte le altre funzioni che hanno un vincolo Foo "gratuito".

La classe di tipo Functor non è molto interessante a tale riguardo, in quanto non ti dà molto.

Un esempio migliore sono le monade e le funzioni nel modulo Control.Monad. Dopo aver definito le due funzioni e return per il tuo tipo, avrai a disposizione altre trenta funzioni che potranno essere utilizzate sul tuo tipo.

Alcuni di quelli più utili includono: mapM, sequence, forever, join, foldM, filterM, replicateM, when, unless e liftM. Questi si visualizzano tutto il tempo nel codice Haskell.

5

I Functional non sono molto interessanti da soli, ma sono un trampolino di lancio necessario per entrare nei funtori applicativi e Traversables.

La proprietà principale che rende utili i funtori applicativi è che è possibile utilizzare fmap con l'operatore applicativo <*> per "sollevare" qualsiasi funzione di qualsiasi tipo per lavorare con valori applicativi. Cioè puoi trasformare qualsiasi a -> b -> c -> d in Applicative f => f a -> f b -> f c -> f d. È inoltre possibile dare un'occhiata a Data.Traversable e Data.Foldable che contengono diverse funzioni generiche che coinvolgono funtori applicativi.

Alternative è un funtore applicativo specializzato che supporta la scelta tra alternative che possono "fallire" (il significato esatto di "vuoto" dipende dall'istanza applicativa). I parser applicativi sono un esempio pratico in cui le definizioni di some e many sono molto intuitive (ad esempio, corrispondono a qualche schema zero o più volte o una o più volte).

Le Monade sono una delle classi di caratteri più interessanti e utili, ma sono già ben coperte dalle altre risposte.

Monoid è un altro tipo di classe che è sia semplice che immediatamente utile. Fondamentalmente definisce un modo per aggiungere due pezzi di dati insieme, il che ti dà un generico concat e una funzionalità nel modulo Foldable menzionato sopra e consente inoltre di utilizzare il monad Writer con il tipo di dati.

2

Come altri hanno già detto, lo stesso Functor in realtà non ti offre molto gratuitamente. Fondamentalmente, il più alto livello o generale di un typeclass è (cioè più cose si adattano a tale descrizione), quindi meno funzionalità "gratuite" si otterrà. Ad esempio, Functor e Monoid non ti forniscono molto, ma Monad e Arrow ti offrono molte funzioni utili gratuitamente.

In Haskell, è comunque una buona idea scrivere un'istanza per Functor e Monoid (se il tipo di dati è effettivamente un funtore o un monoide), perché quasi sempre si cerca di utilizzare l'interfaccia più generale possibile durante la scrittura delle funzioni . Se stai scrivendo una nuova funzione che può farla franca solo usando fmap per operare sul tuo tipo di dati, non c'è motivo di limitare artificialmente quella funzione a Monad s o Applicative s, poiché potrebbe essere utile in seguito per altre cose.

1

La vostra intuizione orientata agli oggetti trasporta, se leggete "interfaccia e implementazione" per "typeclass e istanza". Se fate il vostro nuovo tipo C un'istanza di un typeclass serie B, allora si ottiene gratuitamente che il vostro tipo lavorerà con tutto il codice esistente A che dipende da B.

UML diagram

Come altri hanno detto, quando il typeclass è qualcosa come Monad, quindi gli omaggi sono le molte funzioni di libreria come foldM e when.

Problemi correlati