Quanto sono importanti i concetti avanzati di Haskell come Monadi e Agenti Applicativi per la maggior parte delle attività di programmazione di routine?


16

Ho letto il libro Learn You a Haskell fino al punto in cui introducono Monadi e cose come Just a. Sono così controintuitivi per me che mi viene da rinunciare a cercare di impararlo.

Ma voglio davvero provare.

Mi chiedo se posso almeno evitare i concetti avanzati per un po 'e iniziare a usare le altre parti del linguaggio per svolgere molte attività pratiche con le parti più basilari di Haskell, ovvero funzioni, IO standard, gestione dei file, interfacciamento di database e simili.

È un approccio ragionevole per imparare a usare Haskell?


2
Non so fino a che punto arriverai. Senza le monadi non puoi fare nulla di utile in Haskell, dal momento che fare qualcosa di utile in programmazione (come in, scrivere un programma serio che qualcuno vorrebbe effettivamente usare) richiede I / O e stato, entrambi i quali possono essere gestiti solo in Haskell attraverso l'uso di monadi.
Mason Wheeler,

1
@dan - Finalmente ho capito le monadi Haskell leggendo due documenti - "Avresti potuto inventare monadi" e "Affrontare la Squadra Imbarazzante". Non posso dire se sono meglio di "Learn You a Haskell", che non ho letto, ma hanno funzionato per me. Per usare la notazione do con la monade IO, puoi cavartela con ben poca comprensione di cosa siano le monadi: farai alcune cose che faranno ridere o piangere gli esperti, ma almeno superficialmente non è molto diverso dall'uso un linguaggio imperativo convenzionale. Ma è utile ottenere un certo comprensione più profonda.
Steve314,

2
@dan, mi ci è voluto quasi un decennio per annoiarmi di OOP e iniziare ad apprezzare / essere curioso dei linguaggi funzionali. Vorrei ancora imparare F # e Clojure prima di provare Haskell sul serio. Mentre le sfide personali sono belle, c'è qualcosa da dire sul tuo intestino e sul percorso di minor resistenza. Molto dipende da chi sei. Se sei un tipo fortemente math, probabilmente ti piacerebbe Haskell / Schem fin dall'inizio. Se sei più di un ragazzo "fallo", va bene lo stesso. Non avvicinare Haskell con un atteggiamento "do or die". Continua a imparare altre cose e quando annoiato torna.
Giobbe

Grazie per il consiglio @Job. Ho provato Clojure per un po ', ma la sintassi di Lisp non funziona davvero per me, sia per la lettura che per la digitazione. Trovo la sintassi di Haskell più naturale. Sono felice di usare Ruby per i progetti nel frattempo, ma spero di iniziare a fare alcuni progetti pratici in Haskell.
dan

@dan, Divertente, trovo che la sintassi di Clojure sia piuttosto amichevole, ma probabilmente è perché ero stato esposto a Scheme prima. Forse dopo F # mi abituerò al modo in cui Haskell fa le cose.
Giobbe

Risposte:


16

In primo luogo distinguiamo tra l'apprendimento dei concetti astratti e l'apprendimento di esempi specifici di essi.

Non andrai molto lontano ignorando tutti gli esempi specifici, per la semplice ragione che sono completamente onnipresenti. In effetti, le astrazioni esistono in gran parte perché unificano le cose che faresti comunque con gli esempi specifici.

Le astrazioni stesse, d'altra parte, sono certamente utili , ma non sono immediatamente necessarie. Puoi andare abbastanza lontano ignorando completamente le astrazioni e semplicemente usando direttamente i vari tipi. Ti consigliamo di capirli alla fine, ma puoi sempre tornarci più tardi. In effetti, posso quasi garantire che se lo fai, quando torni ad esso ti schiaffeggerai la fronte e mi chiederò perché hai passato tutto quel tempo a fare le cose nel modo più duro invece di usare i convenienti strumenti di uso generale.

Prendi Maybe acome esempio. È solo un tipo di dati:

data Maybe a = Just a | Nothing

È tutto fuorché auto-documentante; è un valore opzionale. O hai "solo" qualcosa di tipo ao non hai niente. Supponiamo che tu abbia una funzione di ricerca di qualche tipo, che ritorna Maybe Stringper rappresentare la ricerca di un Stringvalore che potrebbe non essere presente. Quindi modellare la corrispondenza sul valore per vedere quale è:

case lookupFunc key of
    Just val -> ...
    Nothing  -> ...

È tutto!

Davvero, non c'è nient'altro di cui hai bisogno. Non Functors o Monads o qualsiasi altra cosa. Esprimono modi comuni di usare i Maybe avalori ... ma sono solo modi di dire, "schemi di progettazione", qualunque cosa tu voglia chiamare.

L'unico posto in cui non puoi assolutamente evitarlo è IO, ma è comunque una misteriosa scatola nera, quindi non vale la pena provare a capire cosa significa come Monado qualunque cosa.

In effetti, ecco un cheat sheet per tutto ciò che devi veramente sapere IOper ora:

  • Se qualcosa ha un tipo IO a, significa che è una procedura che fa qualcosa e sputa fuori un avalore.

  • Quando hai un blocco di codice usando la donotazione, scrivi qualcosa del genere:

    do -- ...
       inp <- getLine
       -- etc...
    

    ... significa eseguire la procedura a destra di <-e assegnare il risultato al nome a sinistra.

  • Considerando che se hai qualcosa del genere:

    do -- ...
       let x = [foo, bar]
       -- etc...
    

    ... significa assegnare il valore dell'espressione semplice (non una procedura) a destra del =nome a sinistra.

  • Se metti qualcosa lì senza assegnare un valore, in questo modo:

    do putStrLn "blah blah, fishcakes"
    

    ... significa eseguire una procedura e ignorare tutto ciò che restituisce. Alcune procedure hanno il tipo IO ()--il ()tipo è una sorta di segnaposto che non dice nulla, perché così, significa che la procedura non qualcosa e non restituisce un valore. Un po 'come una voidfunzione in altre lingue.

  • L'esecuzione della stessa procedura più di una volta può dare risultati diversi; è un po 'l'idea. Questo è il motivo per cui non c'è modo di "rimuovere" il IOda un valore, perché qualcosa in IOnon è un valore, è una procedura per ottenere un valore.

  • L'ultima riga in un doblocco deve essere una procedura semplice senza assegnazione, in cui il valore restituito di quella procedura diventa il valore restituito per l'intero blocco. Se si desidera che il valore restituito utilizzi un valore già assegnato, la returnfunzione accetta un valore semplice e fornisce una procedura non operativa che restituisce quel valore.

  • A parte questo, non c'è niente di speciale in merito IO; queste procedure sono in realtà valori semplici e puoi passarle e combinarle in modi diversi. È solo quando vengono eseguiti in un doblocco chiamato da qualche parte mainche fanno qualsiasi cosa.

Quindi, in qualcosa di simile a questo programma di esempio completamente noioso e stereotipato:

hello = do putStrLn "What's your name?"
           name <- getLine
           let msg = "Hi, " ++ name ++ "!"
           putStrLn msg
           return name

... puoi leggerlo proprio come un programma imperativo. Stiamo definendo una procedura denominata hello. Quando eseguito, per prima cosa esegue una procedura per stampare un messaggio che chiede il tuo nome; successivamente esegue una procedura che legge una riga di input e assegna il risultato a name; quindi assegna un'espressione al nome msg; quindi stampa il messaggio; quindi restituisce il nome dell'utente come risultato dell'intero blocco. Poiché nameè a String, ciò significa che helloè una procedura che restituisce a String, quindi ha tipo IO String. E ora puoi eseguire questa procedura altrove, proprio come viene eseguita getLine.

Pfff, monadi. Chi ne ha bisogno?


2
@dan: sei il benvenuto! Se avete domande specifiche lungo la strada, non esitate a chiedere su Stack Overflow. Il tag [haskell] di solito è piuttosto attivo, e se spieghi da dove vieni le persone sono abbastanza bravi ad aiutarti a capire piuttosto che a lanciare risposte criptiche.
CA McCann,

9

Quanto sono importanti i concetti avanzati di Haskell come Monadi e Agenti Applicativi per la maggior parte delle attività di programmazione di routine?

Sono essenziali. Senza di loro, è fin troppo facile usare Haskell come un altro linguaggio imperativo, e sebbene Simon Peyton Jones una volta chiamasse Haskell, "il miglior linguaggio di programmazione imperativo del mondo", ti perdi ancora la parte migliore.

Le monadi, le trasformazioni di monade, i monoidi, i portatori, i portatori applicativi, i portatori contravvenenti, le frecce, le categorie, ecc. Sono modelli di progettazione. Una volta che si inserisce la cosa specifica che si sta trasformando in una di esse, si è in grado di attingere a un'enorme ricchezza di funzioni scritte in modo astratto. Queste classi di tipi non sono semplicemente lì per confonderti, sono lì per semplificarti la vita e renderti più produttivo. Sono, secondo me, la ragione principale della concisione del buon codice Haskell.


1
+1: Grazie per aver sottolineato che "Monadi, trasformazioni di monade, monoidi, portatori, portatori applicativi, portatori controversi, frecce, categorie, ecc., Sono modelli di progettazione". !
Giorgio

7

È strettamente necessario se vuoi solo far funzionare qualcosa? No.

È necessario se vuoi scrivere bellissimi programmi idiomatici di Haskell? Assolutamente.

Durante la programmazione in Haskell è utile tenere a mente due cose:

  1. Il sistema di tipi è lì per aiutarti. Se componi il tuo programma con un codice altamente polimorfico e un codice pesante, molto spesso puoi entrare nella meravigliosa situazione in cui il tipo della funzione desiderata ti guiderà all'implementazione corretta (una sola!) .

  2. Le varie librerie disponibili sono state sviluppate usando il principio n. 1.

Quindi, quando scrivo un programma in Haskell, inizio scrivendo i tipi. Quindi ricomincio e scrivo alcuni tipi più generali (e se possono essere istanze di macchine da scrivere esistenti, tanto meglio). Quindi scrivo alcune funzioni che mi danno valori dei tipi che desidero. (Poi gioco con loro ghcie magari scrivo alcuni test di QuickCheck.) E infine colla tutto insieme main.

È possibile scrivere il brutto Haskell che fa funzionare qualcosa. Ma c'è molto di più da imparare una volta raggiunto quel livello.

In bocca al lupo!


1
Grazie! Ho vacillato tra Clojure e Haskell, ma ora mi sto sporgendo verso Haskell a causa di quanto siano state utili persone come te.
dan

1
La comunità di Haskell sembra essere molto gentile e disponibile. E sembra che provengano molte idee interessanti
Zachary K,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.