Шаг 21.
Основы языка Haskell. Основные типы данных, операции, способы определения функций. Определение функций с помощью условных выражений

    На этом шаге мы рассмотрим условные конструкции.

    Для организации простого ветвления, имеющего две альтернативы, используется синтаксическая конструкция (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>

    На следующем шаге мы рассмотрим определение функций с помощью охраняющих выражений.




Предыдущий шаг Содержание Следующий шаг