Ho intenzione di insegnare un corso di divisione inferiore in strutture discrete. Ho selezionato il libro di testo Discrete Structures, Logic, and Computability in parte perché contiene esempi e concetti che favoriscono l'implementazione con un linguaggio di programmazione funzionale. (Penso anche che sia un buon libro.)Haskell o Standard ML per principianti?
Voglio un linguaggio FP di facile comprensione per illustrare i concetti di DS e che gli studenti possono usare. La maggior parte degli studenti avrà avuto solo uno o due semestri di programmazione in Java, nel migliore dei casi. Dopo aver esaminato Scheme, Erlang, Haskell, Ocaml e SML, ho optato per Haskell o Standard ML. Mi sto appoggiando ad Haskell per i motivi illustrati di seguito, ma mi piacerebbe l'opinione di coloro che sono programmatori attivi nell'uno o nell'altro.
- Sia Haskell che SML hanno un pattern matching che rende la descrizione di un algoritmo ricorsivo un gioco da ragazzi.
- Haskell ha una buona comprensione delle liste che si adattano bene al modo in cui tali liste sono espresse matematicamente.
- Haskell ha una valutazione lenta. Ottimo per la costruzione di liste infinite usando la tecnica di comprensione delle liste.
- SML ha un interprete veramente interattivo in cui le funzioni possono essere definite e utilizzate. In Haskell, le funzioni devono essere definite in un file separato e compilate prima di essere utilizzate nella shell interattiva.
- SML fornisce una conferma esplicita dell'argomento della funzione e dei tipi restituiti in una sintassi di facile comprensione. Ad esempio: val foo = fn: int * int -> int. La sintassi implicita del curry di Haskell è un po 'più ottusa, ma non totalmente aliena. Ad esempio: foo :: Int -> Int -> Int.
- Haskell utilizza per impostazione predefinita numeri interi a precisione arbitraria. È una libreria esterna in SML/NJ. E SML/NJ tronca l'output a 70 caratteri per impostazione predefinita.
- La sintassi lambda di Haskell è sottile: utilizza una sola barra rovesciata. SML è più esplicito. Non sono sicuro se avremo mai bisogno di lambda in questa classe, però.
Essenzialmente, SML e Haskell sono approssimativamente equivalenti. Mi chino verso Haskell perché adoro le liste e le liste infinite in Haskell. Ma sono preoccupato che l'ampio numero di simboli nella sintassi compatta di Haskell possa causare problemi agli studenti. Da quello che ho raccolto leggendo altri post su SO, Haskell non è raccomandato per i principianti che iniziano con FP. Ma non stiamo andando a costruire applicazioni a pieno titolo, semplicemente provando semplici algoritmi.
Cosa ne pensi?
Modifica: dopo aver letto alcune delle tue grandi risposte, dovrei chiarire alcuni dei miei punti elenco.
In SML, non esiste una distinzione sintattica tra la definizione di una funzione nell'interprete e la sua definizione in un file esterno. Diciamo che vuoi scrivere la funzione fattoriale. In Haskell si può mettere questa definizione in un file e caricarlo in GHCi:
fac 0 = 1
fac n = n * fac (n-1)
Per me, questo è chiaro, conciso, e corrisponde alla definizione matematica nel libro. Ma se si vuole scrivere la funzione in GHCi direttamente, è necessario utilizzare una sintassi diversa:
let fac 0 = 1; fac n = n * fac (n-1)
Quando si lavora con gli interpreti interattivi, dal punto di vista didattico è molto, molto utile quando lo studente può utilizzare lo stesso codice sia in un file che nella riga di comando.
Con "conferma esplicita della funzione", intendevo dire che al momento della definizione della funzione, SML indica immediatamente il nome della funzione, i tipi degli argomenti e il tipo di ritorno. In Haskell devi usare il comando :type
e poi ottenere la notazione al curry un po 'confusa.
Una cosa più bella di Haskell - si tratta di una definizione di funzione valida:
fac 0 = 1
fac (n+1) = (n+1) * fac n
Ancora una volta, questo corrisponde a una definizione che potrebbero trovare nel libro di testo. Non posso farlo in SML!
Informazioni sull'interprete di Haskell, questi sono solo alcuni limiti specifici di GHCi. Forse alcuni altri interpreti Haskell potrebbero avere un comportamento migliore. È possibile definire valori e funzioni in ghci, ma non datatype. Devi iniziare dicendo "lascia". Inoltre, ogni input deve essere su una singola riga, quindi invece della sintassi allineata al rientro su più righe per più definizioni in "let", o per istruzioni in "do" o "case", devi separarli in punti e virgola e circondalo di parentesi. per esempio. "let {fact 0 = 1; fact n = n * fact (n-1)}". Inoltre, le clausole "where" non funzionano. È un po 'noioso – newacct
Informazioni sul currying, SML ha lo stesso supporto per la programmazione e la stessa sintassi di Haskell. Ad esempio, in SML, "fun foo x y = x * y" è una moltiplicazione al curry. È solo che, per qualche ragione, la convenzione in SML è che più argomenti dovrebbero essere dati come un singolo argomento di tupla piuttosto che argomenti al curry. (Si noti che OCaml, tuttavia, segue la convenzione al curry, a differenza di SML.) Tuttavia, questa non è una regola assoluta; le funzioni che sono comunemente parzialmente applicate vengono curried in SML. Ad esempio, la funzione "map" in SML viene elaborata con il tipo "('a ->' b) -> 'a list ->' b list". – newacct
Per impostazione predefinita, Haskell ha sia numeri interi a precisione fissa (Int) che interi a precisione arbitraria (numeri interi). È solo che quando non è vincolato, l'interprete sceglie solo il più ampio possibile, che è Integer. Tuttavia, alcune funzioni accetteranno solo l'Int, ad esempio l'operatore di indicizzazione dell'elenco (!!). – newacct