haskell

92
Haskell Александр Гранин [email protected]

Upload: devday

Post on 14-Jun-2015

366 views

Category:

Technology


4 download

DESCRIPTION

Функциональное программирование в примерах. Язык Haskell: характеристики, история, сильные и слабые стороны, истории успеха и неудач. Спецификация Haskell’98: синтаксис, компиляторы, интепретаторы, документация, IDE. Особенности языка: тип Maybe, списки, классы типов, основы монад. Библиотеки и фреймворки: Parsec, GenXml, HaXml DSL На десерт что-то из Existential Types, State Monad, ST Monad, Monad Transformers.

TRANSCRIPT

Page 1: Haskell

HaskellАлександр Гранин

[email protected]

Page 2: Haskell

О чем доклад?● Часть 1. Ликбез по ФП и Haskell

○ Функциональное программирование○ Язык Haskell. Применимость языка○ Язык Haskell. Основы○ Инструменты разработчика

● Часть 2. Haskell: We need to go deeper○ Обработка данных: NgnTrafficParser○ XML и Domain Specific Languages○ Parsec, HaXml, GenXml

● Часть 3. Немного хардкора○ Монады!!!

Page 3: Haskell

Программирование:

● Императивное

● Объектно-ориентированное

● Функциональное

● Логическое

● Декларативное

Page 4: Haskell

(println "Hello World!")

printfn "Hello World!"

io:format("Hello, World!~n").

putStrLn "Hello World!"

println("Hello World!")

Page 5: Haskell

Функциональное программирование

?

Page 6: Haskell

Функциональное программирование

● Все есть функция

● ...

● ...

● ...

● ...

● ...

Page 7: Haskell

Функциональное программирование

● Все есть функция

● Рекурсия

● ...

● ...

● ...

● ...

Page 8: Haskell

Функциональное программирование

● Все есть функция

● Рекурсия

● Функции высших порядков

● ...

● ...

● ...

Page 9: Haskell

Функциональное программирование

a := 1a := 2

DO NOT CHANGE!The immutability is with you

● Все есть функция

● Рекурсия

● Функции высших порядков

● Иммутабельность данных

● ...

● ...

Page 10: Haskell

Функциональное программирование

● Все есть функция

● Рекурсия

● Функции высших порядков

● Иммутабельность данных

● Чистые функции

● ...

Page 11: Haskell

Функциональное программирование

● Все есть функция

● Рекурсия

● Функции высших порядков

● Иммутабельность данных

● Чистые функции

● Нет побочных эффектов

Page 12: Haskell

Язык Haskell

?

Page 13: Haskell

Язык Haskell

Haskell - это...

● Чистый функциональный,● строго статически типизированный,● кроссплатформенный,● компилируемый язык● общего назначения● с ленивой семантикой● и автоматическим выводом типов.

Page 14: Haskell

Краткая история Haskell

● В честь Хаскеля Карри

● GHC: Саймон Пейтон Джонс

● Семейство языков ML

● Прародитель - Miranda

● 1990 год - Haskell 1.0

● 1998 год - Haskell '98

● 2009 год - Haskell 2010

«Доказательство — это программа, а

доказываемая формула — это тип

программы»

(c) M

iran

Lipo

vača

Page 15: Haskell

Где Haskell плох:

● Системное программирование

● Real-time системы

● GUI

Page 16: Haskell

Где Haskell хорош:

● Надежность кода

Page 17: Haskell

● Надежность кода

● Domain Specific Languages

Abstract Syntax Tree

Code base

Где Haskell хорош:

Page 18: Haskell

● Надежность кода

● Domain Specific Languages

● Безопасный параллелизм

Где Haskell хорош:

Page 19: Haskell

● Надежность кода

● Domain Specific Languages

● Безопасный параллелизм

● Обработка данных

Телекомы: TrafficParser

Где Haskell хорош:

Page 20: Haskell

● Надежность кода

● Domain Specific Languages

● Безопасный параллелизм

● Обработка данных

● Парсинг

Где Haskell хорош:

Name

Description

Body Type

XML

DSL

Page 21: Haskell

Haskell - не мэйнстрим?..

Page 22: Haskell

Причины непопулярности

● Pascal, C, C++, Java, C# - в вузах● Традиционное мировоззрение очень сильно● Заработать на Haskell очень трудно● Мифы и стереотипы

"Избегать успеха любой ценой."Саймон Пейтон Джонс

Page 23: Haskell

Язык Haskell: Основы

Page 24: Haskell

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

Page 25: Haskell

fib 0 = 0fib 1 = 1fib n = fib (n-1) + fib (n-2)

fact 0 = 1fact n = fact (n-1) * n

Сопоставление с образцом

Функции, аргументы - lowerCamelCase

Page 26: Haskell

fib :: Word -> Wordfib 0 = 0fib 1 = 1fib n = fib (n-1) + fib (n-2)

fact :: Word -> Wordfact 0 = 1fact n = fact (n-1) * n

Система типовФункции, аргументы - lowerCamelCase

Типы, классы типов, модули - UpperCamelCase

Page 27: Haskell

fact :: Word -> Wordreplicate :: Int -> a -> [a]map :: (a -> b) -> [a] -> [b](+) :: Int -> Int -> Intadd :: Int -> Int -> Int

Система типов

Page 28: Haskell

Списки. Кортежи

phonebook :: [(String, String)]phonebook = [ ("Bob", "953 777-44-45") , ("Fred", "919 33-555-11") , ("Alice", "383 11111111") , ("Jane", "964 4000004") ]

Page 29: Haskell

Списки. Кортежиtype PhoneBook = [(String, String)]

validate :: PhoneBook -> PhoneBookvalidate book= map addPrefix book

addPrefix :: (String, String) -> (String, String)addPrefix (name, phone) = (name, "+7 " ++ phone)

Page 30: Haskell

Лямбды - анонимные функции

nums = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0]

oddNumbers = filter (\n -> odd n) numsoddNumbers2 = filter odd nums

// C#:int[] nums = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };var oddNumbers = nums.Where(n => n % 2 == 1);

Page 31: Haskell

Генераторы списков

(c) Miran Lipovača http://learnyouahaskell.com/

Page 32: Haskell

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]

Page 33: Haskell

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]

Page 34: Haskell

Алгебраические типы данных

data Bool = True | False

Тип Конструкторы

Page 35: Haskell

Алгебраические типы данных

data STree = Tip | Branch

{ leftBranch :: STree,value :: Int,rightBranch :: STree

}

Page 36: Haskell

Сопоставление с образцом

height :: STree -> Intheight Tip = 0height (Branch lt _ rt) = 1 + max (height lt) (height rt)

5

3 7

1 4

Page 37: Haskell

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

Page 38: Haskell

Инструменты разработки

Page 39: Haskell

Haskell Platform

● Компилятор GHC

● Интерпретатор GHCi

● Базовые библиотеки

● Пакетный менеджер Cabal

● Документирование - Haddock

● MinGW (Windows) http://www.haskell.org/platform/

Page 40: Haskell

Glasgow Haskell Compiler

Компиляция:ghc --make FizzBuzz.hsghc --make -O2 FizzBuzz.hsghc --make -O2 -threaded FizzBuzz.hs

Выполнение:runghc FizzBuzz.hs

Page 41: Haskell

REPL - GHCi(GHC interpreter)

Read

EvalPrintLoop

Page 42: Haskell

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

Page 43: Haskell

Hackage - репозиторий библиотек

Page 44: Haskell

Библиотеки и программы

● xmonad - тайловый оконный менеджер● Parsec - комбинаторные парсеры● HaXmL, HXT - обработка XML● darcs - система контроля версий● Yesod - RESTful веб-фреймворк● QuickCheck - тестирование кода● House, Kinetic - операционные системы● Всевозможные эффективные коллекции● OpenGL, OpenAL, OpenCL биндинги● ... несколько игр и многое другое

Page 45: Haskell

IDE

Page 46: Haskell

EclipseFP

Page 47: Haskell

Leksah

Page 48: Haskell

SublimeHaskell

Page 49: Haskell

Want more?

Page 50: Haskell

NGN Traffic Parser

|R200|99999|333333|CR,CS,AM|1|1|3022|222222|333333|||...|R200|44455|012345|CR,CS,AM|1|1|3022|555555|111111|||...|R200|45678|543210|CR,CS,AM|1|1|3022|444444|555555|||...|R200|88888|222222|CR,CS,AM|1|1|3022|666666|777777|||...

file1.txt file2.txt .........

Billing

CMD, DTS, SQL

Page 51: Haskell

NGN Traffic Parser

Billing

Merge Files

Process data

MS SQL DTS

Page 52: Haskell

АТД: Predicatedata Predicate = NotInList [ByteString] | InList [ByteString] | Like [ByteString] | LengthLess Int

type PredicateMap = [(FieldIndex, Predicate)]

predicates = [ (7, NotInList (map C.pack ["3022", "3012"])) , (8, Like [C.pack "44", C.pack "45"]) , (9, LengthLess 7) ]

Page 53: Haskell

NGN Traffic Parser

checkPredicate :: Predicate -> C.ByteString -> BoolcheckPredicate (NotInList l) str = (not . elem str) lcheckPredicate (InList l) str = elem str lcheckPredicate (LengthLess n) str = (length str) < n

Алгебраический тип данных,Сопоставление с образцом

replaceSymbols :: String -> StringreplaceSymbols s = map (replaceChar '|' ' ') ((map (replaceChar ' ' '*') (refieldDoubles s)))

Ver. 2.0ByteString

Ver. 1.0String

Page 54: Haskell

XML и Domain Specific Languages

Page 55: Haskell

<?xml version="1.0" encoding="utf-8" ?>- <PolicySet xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" PolicySetId="PolicSet-04b0613533354df196715b032388325c" Version="1.0" PolicyCombiningAlgId="urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:permit-overrides"> <Description>All active policices</Description> <Target />- <Policy PolicyId="a25099f1-d6fd-412e-b827-65fd39f799e1" Version="2.1.1 <Description>Match file(s) content</Description> <Target />

Политики безопасности

XML

Page 56: Haskell

Тестирование политики

Алгоритмы тестирования:Безопасность обеспечена?

Нет

Исправляем дыры

Да

ОК, запускаем!!

Policy.xml

Page 57: Haskell

Policy.xml

XML?!. Сложно! Хочу DSL!

Алгоритмы тестирования:Безопасность обеспечена?

Нет

Исправляем дыры

Да

ОК, запускаем!!

MyPolicy.dsl

Page 58: Haskell

Пример DSL

efm := ExactFileMatching 2 ".\test2.db" 0cat2 : "CAT2" = Category [] NoMatchcat1 := Category [cat2] NoMatchcat3 := Category [] NoMatchcat0 := TopCategory [cat1, cat3] NoMatchrule := Rule Permit [] | n_of 1 (Evaluate [efm]) [cat0]policy := Policy DenyOverrides [Audit Deny Medium] [rule]policySet := PolicySet PermitOverrides [] [policy]

Page 59: Haskell

Архитектура DSL <-> XML

Policy.xml

Policy.dsl

Policy AST

HaXmlGenXml

Custom writerParsec

DSL AST

Translator

Page 60: Haskell

DSL: AST на ADTdata DslTokenName = DslTokenName String

data DslTokenBody = DslGuardedBody { dtbDslAdt :: DslAdt , dtbDslExpression :: DslExpression } | DslNonGuardedBody { dtbDslAdt :: DslAdt } data DslToken = EmptyDslToken | DslToken { dtDslTokenType :: DslTokenType , dtDslTokenName :: DslTokenName , dtDslTokenDescr :: DslTokenDescription , dtDslTokenBody :: DslTokenBody }

Page 61: Haskell

Parsec: парсинг DSLdslToken :: GenParser Char st DslTokendslToken = do tName <- dslTokenName tDescr <- dslTokenDescription (tBody, tType) <- dslTokenBody return (DslToken tType tName tDescr tBody)

dslTokenBody :: GenParser Char st (DslTokenBody, DslTokenType)dslTokenBody = spaces >> ( try dslGuardedTokenBody <|> try dslNonGuardedTokenBody <?> "dslTokenBody")

NonGuardedBody

GuardedBody

Name

Description

Body Type

DslToken

DslTokenBody

Page 62: Haskell

Связь с БНФ

lower ::= 'a' | 'b' | ... | 'z'rest ::= (letters | numbers | '_') + rest | ''identifier ::= (lower | '_') + resttokenName ::= identifiertokenBody ::= guardedBody | nonGuardedBodytoken ::= (tokenType, tokenName, tokenDescr, tokenBody)

identifier :: GenParser Char st Stringidentifier = do c <- (lower <|> char '_') rest <- many (alphaNum <|> char '_') return (c : rest)

Page 63: Haskell

HaXml: парсинг XMLtoCondition :: Content i -> Maybe ConditiontoCondition e = let exprCond = head . filterNonTextContent $ children e expr = fromJust $ recognizeStructure expRecognizers

exprCondin Just (Condition expr)

-- ............ Здесь много кода

parsePolicy :: String -> PolicySetparsePolicy content = let (Document _ _ root _) = xmlParse "error.log" content in toPolicySet (CElem root noPos)

Page 64: Haskell

GenXml: генерация XMLwriteDteValue :: DataTypeExt -> Xml ElemwriteDteValue (DteString s) = xtext swriteDteValue (DteBoolean b) = xtext (map toLower (show b))writeDteValue (DteInteger i) = xtext (show i)

writeAttributeValue :: AttributeValue -> Xml ElemwriteAttributeValue (AttributeValue dataType val) = let attrValAttributes = xattr dataTypeN dataType attrValVals = writeDteValue val in xelem attributeValueN (attrValAttributes <#> attrValVals)

Page 65: Haskell

А теперь - хардкор!!!

Page 66: Haskell

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)

Классы типов -"интерфейсы" на стероидах

Page 67: Haskell

data Predicate = NotInList [ByteString] | InList [ByteString] | Like [ByteString] | LengthLess Int deriving (Eq, Show, Read)

Классы типов -"интерфейсы" на стероидах

Page 68: Haskell

Монада IO:Безопасный ввод-выод

Page 69: Haskell

let rndGen1 = mkStdGen 100

let (val1, rndGen2) = random rndGen1

let (val2, rndGen3) = random rndGen2

Отправной пример:Random generator

Page 70: Haskell

Стратегия связывания, 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

Page 71: Haskell

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 ++ "!")

Page 72: Haskell

Возвращаемое значение

getName :: IO StringgetName = do putStrLn "What is your name?" yourName <- getLine putStr "Hello, " putStrLn (yourName ++ "!") return yourName

return :: a -> m aa :: Stringm :: IO

Page 73: Haskell

Монада State

newtype State s a = State { runState :: s -> (a, s) }

Page 74: Haskell

Монада State

myFunc :: State Int IntmyFunc = do val <- get put (val - 8) get

getNumber = evalState myFunc 50main = print getNumber

Page 75: Haskell

Стратегия связывания, State

let state1 = evalState 50

let (val1, state2) = get state1

let ((), state3) = put (val1 - 8) state2

let (val2, state4) = get state3

Page 76: Haskell

Monad transformers?Зачем это надо?

Монада 2Монада 1

Page 77: Haskell

Monad transformers?Зачем это надо?

Монада 2Монада 1

Page 78: Haskell

State + IO

data GS = GS { worldMap :: [Location] , currentLocation :: Location , welded :: Bool , bucketFull :: Bool } deriving (Show)

newtype GameState a = GameState { runGameState :: StateT GS IO a }

Page 79: Haskell

State + IO

run :: GameState Resultrun = 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

...........

Page 80: Haskell

Named + IO

-- Int-named IO calculations:intNamedFunc :: NamedT Int IO IntintNamedFunc = do name <- getName return name

testIntNamed :: IO ()testIntNamed = do name <- evalNamedT intNamedFunc 1 print name -- You got output: 1

Page 81: Haskell

Спасибо за внимание!

Haskell

Александр Гранин[email protected]

Page 82: Haskell

HaskellScala

Clojure...

Want more?

PLUGIN!!!

Page 83: Haskell

FUNction

It's all Haskell is about

Page 84: Haskell

Lambda The Gathering

Page 85: Haskell

Lambda Lifter

Page 86: Haskell

http://bit.ly/17CyYFj

Haskell Links

Page 87: Haskell

http://hackage.haskell.org/packages/hackage.html

Hackage - репозиторий библиотек

Page 88: Haskell

Haskell Platform

● Компилятор GHC

● Интерпретатор GHCi

● Базовые библиотеки

● Пакетный менеджер Cabal

● Документирование - Haddock

● MinGW (Windows) http://www.haskell.org/platform/

Page 89: Haskell

http://habrahabr.ru/company/selectel/blog/13585

8/

Success Stories

Page 90: Haskell

Success Stories

Want more?

http://www.haskell.org/haskellwiki/Haskell_in_industry

Page 91: Haskell

Класс типов Monad

class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a

Page 92: Haskell

Монада 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)