Haskell Language
Sintassi nelle funzioni
Ricerca…
guardie
Una funzione può essere definita usando guardie, che possono essere pensate per classificare il comportamento in base all'input.
Prendi la seguente definizione di funzione:
absolute :: Int -> Int -- definition restricted to Ints for simplicity
absolute n = if (n < 0) then (-n) else n
Possiamo riorganizzarlo usando le guardie:
absolute :: Int -> Int
absolute n
| n < 0 = -n
| otherwise = n
In questo contesto, otherwise
è un alias significativo per True
, quindi dovrebbe sempre essere l'ultima guardia.
Pattern Matching
Haskell supporta le espressioni di corrispondenza del modello sia nella definizione della funzione sia nelle istruzioni case
.
Una dichiarazione di caso è molto simile a un interruttore in altre lingue, tranne che supporta tutti i tipi di Haskell.
Iniziamo semplice:
longName :: String -> String
longName name = case name of
"Alex" -> "Alexander"
"Jenny" -> "Jennifer"
_ -> "Unknown" -- the "default" case, if you like
Oppure, potremmo definire la nostra funzione come un'equazione che sarebbe la corrispondenza del modello, solo senza usare un'istruzione case
:
longName "Alex" = "Alexander"
longName "Jenny" = "Jennifer"
longName _ = "Unknown"
Un esempio più comune è con il tipo Maybe
:
data Person = Person { name :: String, petName :: (Maybe String) }
hasPet :: Person -> Bool
hasPet (Person _ Nothing) = False
hasPet _ = True -- Maybe can only take `Just a` or `Nothing`, so this wildcard suffices
La corrispondenza del modello può essere utilizzata anche negli elenchi:
isEmptyList :: [a] -> Bool
isEmptyList [] = True
isEmptyList _ = False
addFirstTwoItems :: [Int] -> [Int]
addFirstTwoItems [] = []
addFirstTwoItems (x:[]) = [x]
addFirstTwoItems (x:y:ys) = (x + y) : ys
In realtà, Pattern Matching può essere utilizzato su qualsiasi costruttore per qualsiasi classe di tipo. Ad esempio il costruttore per le liste è :
e per le tuple ,
Usando dove e guardie
Data questa funzione:
annualSalaryCalc :: (RealFloat a) => a -> a -> String
annualSalaryCalc hourlyRate weekHoursOfWork
| hourlyRate * (weekHoursOfWork * 52) <= 40000 = "Poor child, try to get another job"
| hourlyRate * (weekHoursOfWork * 52) <= 120000 = "Money, Money, Money!"
| hourlyRate * (weekHoursOfWork * 52) <= 200000 = "Ri¢hie Ri¢h"
| otherwise = "Hello Elon Musk!"
Possiamo usare where
evitare la ripetizione e rendere il nostro codice più leggibile. Vedi la funzione alternativa qui sotto, usando where
:
annualSalaryCalc' :: (RealFloat a) => a -> a -> String
annualSalaryCalc' hourlyRate weekHoursOfWork
| annualSalary <= smallSalary = "Poor child, try to get another job"
| annualSalary <= mediumSalary = "Money, Money, Money!"
| annualSalary <= highSalary = "Ri¢hie Ri¢h"
| otherwise = "Hello Elon Musk!"
where
annualSalary = hourlyRate * (weekHoursOfWork * 52)
(smallSalary, mediumSalary, highSalary) = (40000, 120000, 200000)
Come osservato, abbiamo utilizzato il where
in where
alla fine del corpo della funzione è stata eliminata la ripetizione del calcolo ( hourlyRate * (weekHoursOfWork * 52)
) e abbiamo anche utilizzato where
organizzare l'intervallo di salari.
La denominazione delle sottoespressioni comuni può anche essere ottenuta con le espressioni let
, ma solo la sintassi where
consente alle guardie di fare riferimento a quelle sotto-espressioni nominate.