Haskell Language
Синтаксис в функциях
Поиск…
гвардия
Функция может быть определена с помощью защитных устройств, которые можно рассматривать как классифицирующие поведение в соответствии с вводом.
Возьмем следующее определение функции:
absolute :: Int -> Int -- definition restricted to Ints for simplicity
absolute n = if (n < 0) then (-n) else n
Мы можем переставить его с помощью охранников:
absolute :: Int -> Int
absolute n
| n < 0 = -n
| otherwise = n
В этом контексте в otherwise
это значимый псевдоним для True
, поэтому он всегда должен быть последним стражем.
Соответствие шаблону
Haskell поддерживает выражения соответствия шаблону как в определении функции, так и в операторах case
.
Заявление о ситуации очень похоже на переключатель на других языках, за исключением того, что он поддерживает все типы Haskell.
Начнем с простого:
longName :: String -> String
longName name = case name of
"Alex" -> "Alexander"
"Jenny" -> "Jennifer"
_ -> "Unknown" -- the "default" case, if you like
Или мы могли бы определить нашу функцию как уравнение, которое было бы сопоставлением шаблонов, просто без использования case
:
longName "Alex" = "Alexander"
longName "Jenny" = "Jennifer"
longName _ = "Unknown"
Более распространенным примером является тип 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
Соответствие шаблону также можно использовать в списках:
isEmptyList :: [a] -> Bool
isEmptyList [] = True
isEmptyList _ = False
addFirstTwoItems :: [Int] -> [Int]
addFirstTwoItems [] = []
addFirstTwoItems (x:[]) = [x]
addFirstTwoItems (x:y:ys) = (x + y) : ys
Собственно, сопоставление шаблонов можно использовать для любого конструктора для любого типа. Например, конструктор для списков :
и для кортежей ,
Использование где и охранники
Учитывая эту функцию:
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!"
Мы можем использовать where
, чтобы избежать повторений и сделать наш код более читаемым. Смотрите альтернативную функцию ниже, с помощью 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)
Как было отмечено, мы использовали то, where
в конце функционального тела устранялось повторение вычисления ( hourlyRate * (weekHoursOfWork * 52)
), и мы также использовали, where
организовать диапазон зарплаты.
Именование общих подвыражения также может быть достигнуто с let
выражениями, но только where
синтаксис позволяет охранникам ссылаться на эти именованные подвыражения.