I generici sono una funzionalità del linguaggio che permette di riutilizzare il codice.
Per esempio, non dovrebbe importare quale tipo contiene un array per calcolarne la lunghezza.
Ecco perché la funzione length usa un parametro di tipo generico a nella sua firma di tipo.
length : List a -> Int
Quando un tipo è generico rispetto a un altro tipo, usiamo un nome minuscolo per quest'altro tipo e lo chiamiamo parametro di tipo.
Esempi comuni sono i tipi personalizzati List, Maybe e Result.
-- Maybe is generic over the type a
type Maybe a
= Nothing
| Just a
someString : Maybe String
someString = Just "hello"
someInt : Maybe Int
someInt = Just 42
Un'osservazione importante sui nomi dei parametri di tipo è che possono essere lunghi più di un carattere. L'unico vincolo è che devono essere nomi minuscoli. Perciò, quando è utile, tendiamo a dare loro nomi descrittivi.
Un tipo può essere generico rispetto a più tipi diversi, e quindi avere più parametri di tipo. In quel caso, ogni tipo indipendente riceve un nome minuscolo diverso. Essere indipendenti non impedisce che diventino lo stesso tipo, permette soltanto che siano diversi.
-- Result is generic over the types error and value
type Result error value
= Ok value
| Err error
Anche gli alias di tipo record possono avere parametri di tipo, anche se è meno comune.
-- Event is generic over the type a
type alias Event a =
{ at : Time
, data : a
}
Dato che i tipi possono essere generici, possono esserlo anche le funzioni.
Si possono scrivere funzioni che gestiscono tipi generici, come Maybe.withDefault.
withDefault : a -> Maybe a -> a
withDefault default maybe =
case maybe of
Just value -> value
Nothing -> default
Le funzioni che accettano altre funzioni come parametri si chiamano funzioni di ordine superiore, ed anche queste possono essere generiche.
map : (a -> b) -> Maybe a -> Maybe b
map function maybe =
case maybe of
Just value ->
Just (function value)
Nothing ->
Nothing
In questo esercizio scriverai un TreasureChest generico (e anche magico!), per custodire un po' di tesoro.
Definisci un tipo personalizzato TreasureChest con una sola variante.
La variante deve avere un valore String associato, che servirà a memorizzare la password del forziere.
La variante deve avere anche un valore generico associato, che servirà a memorizzare il tesoro. Questo valore è generico, così il tesoro può essere qualsiasi cosa.
Questa funzione deve accettare due parametri
String (per provare una password)TreasureChest
Questa funzione deve confrontare il tentativo di password fornito con la String contenuta nel TreasureChest.
La funzione deve restituire un Maybe.
Se le password corrispondono, restituisci Just con il valore generico contenuto nel TreasureChest (il tesoro!).
Se le password non corrispondono, restituisci Nothing.
Questa funzione (di ordine superiore) deve accettare due parametri
TreasureChest, anch'esso con lo stesso tipo genericoQuesta funzione deve chiamare la funzione moltiplicatrice passandole il tesoro contenuto nel forziere.
La funzione deve restituire un nuovo TreasureChest, con la stessa password dell'originale e con il tesoro moltiplicato (il valore restituito).
Iscriviti a Exercism per imparare e padroneggiare Elm con 28 concetti110 esercizi e il mentoring di persone reali, tutto gratis.