На этом шаге мы рассмотрим условные конструкции.
Для организации простого ветвления, имеющего две альтернативы, используется синтаксическая конструкция (x1,x2,...,xn - аргументы функции):
<Имя_функции> x1 x2 ... xk = if <Условное_выражение> then <Выражение_1> else <Выражение_2>
Если значение <Условное_выражение> истинно, то возвращается значение <Выражение_0>, в противном случае - значение <Выражение_2>.
Демонстрационные примеры.
-- Демонстрация синтаксиса и семантики условных выражений, -- в записи которых используется конструкция if-then-else -- ****************************************************** -- Функция, возвращающая абсолютное значение аргумента n -------------------------------------------------------- abs1':: (->) Integer Integer abs1' n = if n<0 then -n else n ------------------------------------------------- -- Функция, возвращающая наибольшее из двух чисел ------------------------------------------------- max2:: Int -> Int -> Int max2 x y = if x>y then x else y ------------------- {- Функция, возвращающая значение функции |n|^|n| -} --------------------------- abs1'':: Integer -> Integer abs1'' n = (if n<0 then -n else n)^(if n<0 then -n else n) ---------------------------------------------------------- -- Функция, возвращающая наибольшее из трёх чисел -- (с помощью вложенных альтернатив) ------------------------------------ max3:: Int -> Int -> Int -> Int max3 m n k = if m>n && m>k then m else if n>k then n else k ------------------------------------------------------- -- Функция, возвращающая сумму цифр целого числа n<1000 ------------------------------------------------------- summa:: Integer -> Integer summa n = if n>=1000 then error "n>=1000" else n `div` 100+n `mod` 100 `div` 10 +n `mod` 10 ------------------------------------------------------- -- Функция, возвращающая сумму цифр целого числа n<1000 -- (с использованием функционалов) ---------------------------------- summa':: Int -> Int summa' n = sum (map (\x -> digitToInt x) (show n)) -- *********************************************** -- Неудачные тестовые примеры: ----------------------------------------------- test1 = abs1' 12345 == 12345 && abs1' (-12345) == 12345 && abs1' 0 == 0 && abs1' 2222222222222222222 == 2222222222222222222 && abs1' (-2222222222222222222) == 2222222222222222222 ------------------------------------------------------------- test2 = max2 3 5 == 3 `max2` 5 && max2 3 5 == (max2) 3 5 -------------------------------------------------------- test3 = max3 1 2 3 == 3 && max3 34 12 32 == 34 ----------------------------- test4 = summa 45 == 9 && summa 512 == 8 && summa 555 == 15
Для организации множественного ветвления используется ключевые слова case и of:
<Имя_функции> x1 x2 ... xk = case (x1,x2,...,xk) of (v11,v21,...,vk1) -> <Выражение_0> ... (v1n,v2n,...,vkn) -> <Выражение_n>
Здесь x1,x2,...,xn - аргументы функции, vm1,vm2,...,vmn - образцы выражения, соответствующие аргументу функции xm, многоточия заменяют пропущенные образцы и варианты их значений.
После ключевого слова case идёт выражение, на основании значения которого производится ветвление. После выражения записывается ключевое слово of, вслед за которым идёт набор образцов, с которыми сопоставляется выражение оператора.
Первый сверху образец, с которым успешно сопоставилось значение выражения, определяет ветвь ветвления, которая выбирается для вычисления. Это значит, что образцы, в принципе, могут определять и пересекающиеся множества значений.
Данная конструкция позволяет записывать программы с помощью одного условия.
Демонстрационные примеры:
-- Демонстрация синтаксиса и семантики условного выражения, -- организующего множественное ветвление -- ****************************************************** -- Функция, выводящая по первой указанной букве алфавита -- (английского и русского) название функционального язы- -- ка программирования ---------------------- langv:: Char -> String langv s = case (s) of ('C') -> "Curry, Objective Caml, Clean" ('E') -> "Erlang" ('G') -> "Gofer" ('H') -> "Haskell" ('I') -> "ISWIM" ('J') -> "Joy" ('L') -> "LISP" ('M') -> "Miranda, ML, Standart ML" ('S') -> "Scheme" ('Р') -> "Рефал" (_) -> "Функциональный язык нам неизвестен" ----------------------------------------------------------- -- Функция, возвращающая сумму чисел, составляющих -- указанную дату рождения вида: -- -- Число "Название_месяца" Год --------------------------------------------- day:: Integer -> [Char] -> Integer -> Integer day d m y | d<1 || d>31 = error "Такого дня в календаре нет" | True = case (d,m,y) of (_, "Января ", _) -> d+y+ 1 (_, "Февраля ", _) -> d+y+ 2 (_, "Марта ", _) -> d+y+ 3 (_, "Апреля ", _) -> d+y+ 4 (_, "Мая ", _) -> d+y+ 5 (_, "Июня ", _) -> d+y+ 6 (_, "Июля ", _) -> d+y+ 7 (_, "Августа ", _) -> d+y+ 8 (_, "Сентября", _) -> d+y+ 9 (_, "Октября ", _) -> d+y+10 (_, "Ноября ", _) -> d+y+11 (_, "Декабря ", _) -> d+y+12 (_,_,_) -> error "Месяца в календаре нет" -- *********************************************************** -- Неудачные тестовые примеры: ------------------------------ test = test1 && test2 ----------------------------- test1 = langv 'L' == "LISP" && langv 'H' == "Haskell" && langv 'C' == "Curry, Objective Caml, Clean" && langv 'S' == "Scheme" && langv 'Р' == "Рефал" && langv 'R' == "Функциональный язык нам неизвестен" ----------------------------------------------------------- test2 = day 01 "Января " 1550 == 1552 && day 23 "Февраля " 1230 == 1255 && day 08 "Марта " 1100 == 1111 && day 01 "Апреля " 2007 == 2012 && day 01 "Сентября" 900 == 910 ---------------------------------------- test3 = day (-24) "Ноября " 2004 test4 = day 24 "Но" 2004
-- Демонстрация синтаксиса и семантики условного выражения, -- организующего множественное ветвление. ----------------------------------------- -- Укажите назначение приведённых функций ----------------------------------------- getDay:: Integer -> [Char] getDay day = case (day) of (1) -> "Monday" (2) -> "Tuesday" (3) -> "Wednesday" (4) -> "Thursday" (5) -> "Friday" (6) -> "Saturday" (7) -> "Sunday" (_) -> "No such day of week" ------------------------------------------- getDate:: [Char] -> Integer getDate date = case (date) of ("Monday") -> 1 ("Tuesday") -> 2 ("Wednesday") -> 3 ("Thursday") -> 4 ("Friday") -> 5 ("Saturday") -> 6 ("Sunday") -> 7 ------------------------------------ defDay:: Integer -> [Char] -> [Char] defDay d dow | d<1 || d>31 = error "No such day in calendar" | d `mod` 7==1 = dow | d>1 && d<=7 = getDay((getDate(dow)+d-1)`mod`7) | otherwise = getDay(getDate(dow)`mod`7-1) ---------------------------------------------------------- -- Неудачные тестовые примеры: -------------------------------------- test = defDay 1 "Monday" == "Monday" && defDay 2 "Monday" == "Tuesday" && defDay 4 "Sunday" == "Wednesday"
Простое ветвление может быть записано в виде:
<Имя_функции> x1 x2 ... xk = case (<Условное_выражение>) of (True) -> <Выражение_1> (False) -> <Выражение_2>
На следующем шаге мы рассмотрим определение функций с помощью охраняющих выражений.