2. О чем доклад?
● Часть 1. Ликбез по ФП и Haskell
○ Функциональное программирование
○ Язык Haskell. Применимость языка
○ Язык Haskell. Основы
○ Инструменты разработчика
● Часть 2. Haskell: We need to go deeper
○ Обработка данных: NgnTrafficParser
○ XML и Domain Specific Languages
○ Parsec, HaXml, GenXml
● Часть 3. Немного хардкора
○ Монады!!!
9. Функциональное
программирование
a := 1
a := 2
DO NOT CHANGE!
The immutability is with you
● Все есть функция
● Рекурсия
● Функции высших
порядков
● Иммутабельность
данных
● ...
● ...
13. Язык Haskell
Haskell - это...
● Чистый функциональный,
● строго статически типизированный,
● кроссплатформенный,
● компилируемый язык
● общего назначения
● с ленивой семантикой
● и автоматическим выводом типов.
14. Краткая история Haskell
● В честь Хаскеля Карри
● GHC: Саймон Пейтон Джонс
● Семейство языков ML
● Прародитель - Miranda
● 1990 год - Haskell 1.0
● 1998 год - Haskell '98
● 2009 год - Haskell 2010
«Доказательство —
это программа, а
доказываемая
формула — это тип
программы»
(c)MiranLipovača
17. ● Надежность кода
● Domain Specific Languages
Abstract Syntax
Tree
Code base
Где Haskell хорош:
18. ● Надежность кода
● Domain Specific Languages
● Безопасный параллелизм
Где Haskell хорош:
19. ● Надежность кода
● Domain Specific Languages
● Безопасный параллелизм
● Обработка данных
Телекомы:
TrafficParser
Где Haskell хорош:
20. ● Надежность кода
● Domain Specific Languages
● Безопасный параллелизм
● Обработка данных
● Парсинг
Где Haskell хорош:
Name
Description
Body Type
XML
DSL
22. Причины непопулярности
● Pascal, C, C++, Java, C# - в вузах
● Традиционное мировоззрение очень сильно
● Заработать на Haskell очень трудно
● Мифы и стереотипы
"Избегать успеха любой ценой."
Саймон Пейтон Джонс
24. fib n = case n of
0 -> 0
1 -> 1
n -> fib (n-1) + fib (n-2)
fact n = case n of
0 -> 1
n -> fact (n-1) * n
Функции.
case - аналог switch
Функции,
аргументы -
lowerCamelCase
25. fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fact 0 = 1
fact n = fact (n-1) * n
Сопоставление с образцом
Функции,
аргументы -
lowerCamelCase
26. fib :: Word -> Word
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fact :: Word -> Word
fact 0 = 1
fact n = fact (n-1) * n
Система типов
Функции,
аргументы -
lowerCamelCase
Типы, классы
типов, модули -
UpperCamelCase
27. fact :: Word -> Word
replicate :: Int -> a -> [a]
map :: (a -> b) -> [a] -> [b]
(+) :: Int -> Int -> Int
add :: Int -> Int -> Int
Система типов
32. Cоздать список:
1. На множестве от 1 до 100.
2. Только нечетные.
3. Делящиеся на 3 без остатка.
4. Делящиеся на 7 без остатка.
list1 = [21, 63]
list2 = [x | x <- [1..100], odd x,
x `mod` 3 == 0,
x `mod` 7 == 0]
33. 1. x - от 1 до 100, y - от 100 до 200.
2. x - четные, y - нечетные.
3. x + y < 200.
4. |x - y| > 190.
Cоздать список [(x, y)]:
list = [(x, y) | x <- [1..100], even x,
y <- [100..200], odd y,
x + y < 200,
abs (x - y) > 190]
36. Сопоставление с образцом
height :: STree -> Int
height Tip = 0
height (Branch lt _ rt) = 1 + max (height lt) (height rt)
5
3 7
1 4
37. Data.Maybe - аналог Nullable
phonebook :: [(String, String)]
...
printPhone :: String -> [(String, String)] -> IO ()
printPhone name book = case lookup name book of
Nothing -> putStrLn "Name not exist."
Just phone -> putStrLn phone
data Maybe a = Nothing
| Just a
lookup :: Eq a => a -> [(a, b)] -> Maybe b
42. REPL - GHCi
(GHC interpreter)
> [1..10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
> (3 + 30)
33
> fizzBuzz
<interactive>:1:1:
No instance for (Show (Int -> String))
arising from a use of 'print'
Possible fix:
add an instance declaration for (Show (Int -> String))
In a stmt of an interactive GHCi command: print it
44. Библиотеки и программы
● xmonad - тайловый оконный менеджер
● Parsec - комбинаторные парсеры
● HaXmL, HXT - обработка XML
● darcs - система контроля версий
● Yesod - RESTful веб-фреймворк
● QuickCheck - тестирование кода
● House, Kinetic - операционные системы
● Всевозможные эффективные коллекции
● OpenGL, OpenAL, OpenCL биндинги
● ... несколько игр и многое другое
55. <?xml version="1.0" encoding="utf-8" ?>
- <PolicySet xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-
PolicySetId="PolicSet-04b0613533354df196715b032388325c" Vers
PolicyCombiningAlgId="urn:oasis:names:tc:xacml:1.0:policy-combin
permit-overrides">
<Description>All active policices</Description>
<Target />
- <Policy PolicyId="a25099f1-d6fd-412e-b827-65fd39f799e1" Versio
<Description>Match file(s) content</Description>
<Target />
Политики безопасности
XML
63. HaXml: парсинг XML
toCondition :: Content i -> Maybe Condition
toCondition e = let
exprCond = head . filterNonTextContent $ children e
expr = fromJust $ recognizeStructure expRecognizers
exprCond
in Just (Condition expr)
-- ............ Здесь много кода
parsePolicy :: String -> PolicySet
parsePolicy content = let
(Document _ _ root _) = xmlParse "error.log" content
in toPolicySet (CElem root noPos)
64. GenXml: генерация XML
writeDteValue :: DataTypeExt -> Xml Elem
writeDteValue (DteString s) = xtext s
writeDteValue (DteBoolean b) = xtext (map toLower (show b))
writeDteValue (DteInteger i) = xtext (show i)
writeAttributeValue :: AttributeValue -> Xml Elem
writeAttributeValue (AttributeValue dataType val) = let
attrValAttributes = xattr dataTypeN dataType
attrValVals = writeDteValue val
in xelem attributeValueN (attrValAttributes <#> attrValVals)
66. lookup :: Eq a => a -> [(a, b)] -> Maybe b
class Eq a where
(==), (/=) :: a -> a -> Bool
instance Eq Char where
c1 == c2 = ... -- compare chars
c1 /= c2 = not (c1 == c2)
instance Eq Int where
i1 == i2 = ... -- compare ints
i1 /= i2 = not (i1 == i2)
Классы типов -
"интерфейсы" на стероидах
67. data Predicate = NotInList [ByteString]
| InList [ByteString]
| Like [ByteString]
| LengthLess Int
deriving (Eq, Show, Read)
Классы типов -
"интерфейсы" на стероидах
69. let rndGen1 = mkStdGen 100
let (val1, rndGen2) = random rndGen1
let (val2, rndGen3) = random rndGen2
Отправной пример:
Random generator
70. Стратегия связывания, IO
getName :: IO ()
getName = do
putStrLn "What is your name?"
yourName <- getLine
putStr "Hello, "
putStrLn (yourName ++ "!")
let world0 = getWorld
let (val1, world1) = ioAction1 world0
let (val2, world2) = ioAction2 world1
71. do-нотация
getName :: IO ()
getName = do
putStrLn "What is your name?"
yourName <- getLine
putStr "Hello, "
putStrLn (yourName ++ "!")
getName' =
putStrLn "What is your name?"
>> getLine
>>= yourName -> putStr "Hello, "
>> putStrLn (yourName ++ "!")
72. Возвращаемое значение
getName :: IO String
getName = do
putStrLn "What is your name?"
yourName <- getLine
putStr "Hello, "
putStrLn (yourName ++ "!")
return yourName
return :: a -> m a
a :: String
m :: IO
74. Монада State
myFunc :: State Int Int
myFunc = do
val <- get
put (val - 8)
get
getNumber = evalState myFunc 50
main = print getNumber
75. Стратегия связывания, State
let state1 = evalState 50
let (val1, state2) = get state1
let ((), state3) = put (val1 - 8) state2
let (val2, state4) = get state3
78. State + IO
data GS = GS { worldMap :: [Location]
, currentLocation :: Location
, welded :: Bool
, bucketFull :: Bool }
deriving (Show)
newtype GameState a = GameState
{ runGameState :: StateT GS IO a }
79. State + IO
run :: GameState Result
run = do
t <- get
-- read a command from the user
io . putStr $ "> "
io . hFlush $ stdout
line <- io getLine
result <- case parseCommand line of
Nothing -> write "Invalid command!" >> continue
Just cmd -> do
...........
80. Named + IO
-- Int-named IO calculations:
intNamedFunc :: NamedT Int IO Int
intNamedFunc = do
name <- getName
return name
testIntNamed :: IO ()
testIntNamed = do
name <- evalNamedT intNamedFunc 1
print name -- You got output: 1
91. Класс типов Monad
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
92. Монада Named -
именованные вычисления
data Named n a = Named
{ runNamed :: (n -> a) }
instance Monad (Named n) where
return x = Named (_ -> x)
x >>= f = Named (name -> let
a = runNamed x name
in runNamed (f a) name)