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.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow