код от часа 08
-- Следните редове включват някои полезни предупреждения в ghc:
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-} -- cover all cases!
--{-# OPTIONS_GHC -fwarn-unused-matches #-} -- use all your pattern matches!
--{-# OPTIONS_GHC -fwarn-missing-signatures #-} -- write all your toplevel signatures!
{-# OPTIONS_GHC -fwarn-name-shadowing #-} -- use different names!
{-# OPTIONS_GHC -fwarn-incomplete-uni-patterns #-} -- no incomplete patterns in lambdas!
--import Prelude hiding (div)
-- Пишем в любим текстов редактор (примерно vim или vscode)
-- и пускаме програмите с ghci (или ги компилираме с ghc)
-- ghci е repl
-- :t(ype)
-- :i(nfo)
-- :l(oad)
-- :r(eload)
--
z2 = 12389712983
-- В контраст със Scheme, Haskell е:
-- 1. Статично типизиран
-- 2. С мързеливо оценяване
-- 3. Без странични ефекти
-- * Няма имплицитно кастване
-- * Зависим от идентация (и не харесва табулации)
---- Типове:
-- Bool - True или False;
-- Char - Unicode символи - примерно 'g' или 'ю' или 'λ';
-- Int - цели числа между -2^63 и (2^63 - 1) включително;
-- Integer - произволно големи цели числа (като в Scheme)
-- Float - десетични дробни числа, 32 бита;
-- Double - десетични дробни числа, 64 бита.
add :: Int -> Int -> Int
add x y = x + y
add3 :: Int -> Int -> Int -> Int
add3 x y z' = x + y + z'
inc :: Int -> Int
inc x = x+1
-- Съставни типове:
-- списъци: [a] - всички елементи на списъка са от един и същи тип а, примерно
-- [1,2,3] е от тип [Int], може също да е и от тип [Integer];
-- [True,True,True,False] е от тип [Bool];
-- [1,True,'a'] не е списък.
--
-- низове: String - същото като списък от символи [Char], примерно
-- "hello world" е от тип String и "abc" == ['a','b','c']
--
-- наредени n-торки (кортежи) - имат фиксирана дължина, но типовете на членовете на n-торката може да се различават, примерно
-- (1,2,3) е от тип (Int,Int,Int);
-- ('Щ', 1, False, [3.1, 4.8]) е от тип (Char, Int, Bool, [Float]);
-- () е от тип () и е единственият обитател на типа ().
{-
Коментар на няколко реда
-}
-- Всички типове винаги започват с главна буква.
type String' = [Char]
---- Константи
z :: Float
z = 127387912735.01
-- Ако не укажем типа на идентификатор,
-- Haskell ще се опита сам да го измисли, т.нар. type inference.
-- Това е полезно, но понякога може Haskell да обърка типа,
-- затова ще си пишем типовите декларации.
---- Функции на 1 аргумент
plusTen :: Int -> Int
plusTen x = x + 10
-- целочислено деление
div' :: Int -> Int -> Int
div' x y = floor (fromIntegral x / fromIntegral y)
divInteger :: Integer -> Integer -> Integer
divInteger x y = floor (fromInteger x / fromInteger y)
-- Идентификаторите (тоест имената на константите и функциите)
-- винаги започват с малка буква ('_' се води малка буква)
-- и съдържат само букви, числа или символа '.
-- Имена като 1+, odd? и zip-with, каквито ползвахме в Scheme,
-- не са позволени. Ще ползваме camelCase.
mult :: Num a => Int -> Int -> a
mult a b = fromIntegral (a * b)
-- Прилагането на функции в Haskell е с най-висок приоритет
-- и е ляво асоциативно.
-- mult 2 3 + 7 -- 13
-- ((mult 2) 3) + 7
-- mult 2 (3 + 7) -- 20
-- mult 2 succ 3 -- Грешка
-- същото като
-- (((mult 2) succ) 3)
-- if <condition> then <expr> else <expr>
-- Сравняваме числа с (==), (/=), (<), (>), (<=) и т.н.
-- модул от n
abs' :: Integer -> Integer
abs' n =
--(if (n < 0) then (- n) else n)
if n < 0
then -n
else n
-- целочислено деление на 2
half :: Integer -> Integer
half x
| even x = (floor ((fromIntegral x) / 2.0))
| odd x = -1
| x == 10000 = -2
| otherwise = div (x-1) 2
-- разглеждане на случаи - guards
fact'' :: Integer -> Integer
fact'' n =
if n == 0
then 1
else n * fact'' (n-1)
fact' :: Integer -> Integer
fact' n
| n == 0 = 1
| n < 0 = -999999999
| otherwise = n * fact' (n-1)
fact :: Integer -> Integer
fact 0 = 1
fact n = fact (n-1) * n
factI :: Int -> Int
factI 0 = 1
factI n = n * factI (n-1)
fib n
| n == 0 = 0
| n == 1 = 1
| otherwise = fib (n-1) + fib (n-2)
fib' :: Int -> Int
fib' 0 = 0
fib' 1 = 1
fib' n = fib (n-1) + fib (n-2)
-- най-голям общ делител на n и m
-- използвайте div за целочислено делене
gcd' :: Int -> Int -> Int
gcd' a b =
if b == 0
then abs a
else abs (gcd' b (rem a b))
--(gcd' a b) * (lcm' a b) == a * b
-- най-малко общо кратно
lcm' :: Int -> Int -> Int
lcm' a b = undefined
--div' (a * b) (gcd' a b)
-- по дадено число намира сбора на цифрите му
sumDigits :: Int -> Int
sumDigits n = undefined
-- всяка функция на 2 аргумента да я приложим като бинарна операция (инфиксно).
-- Пример: 12 `mod` 3
-- от друга страна всеки оператор можем да го използваме като функция:
-- (+) 2 3
--
--
--
--
--
--
--Задача 4. (12 т.) Чифт обувки се представят с модел (низ) и номер
--(цяло число). Да се напише функция bestRange, която по даден
--непразен списък от чифтове намира модел обувки, от който има
--максимален брой различни номера. Пример:
type Shoe = (String, Int)
--bestRange [("boots", 38), ("sandals", 41), ("boots", 38),
--("sandals", 43)] → "sandals"
--bestRange :: [Shoe] -> String
--bestRange [] = "nqma"
--bestRange (x:xs) = undefined