ݺߣ

ݺߣShare a Scribd company logo
Haskell это...
Простой синтаксис.
Статическая типизация. Но не навязчивая.
Списки. Программирование без циклов и
переменных.
Списки, Maybe и другие алгебраические типы.
Функциональное программирование, рекурсия,
иммутабельность.
Развитая инфраструктура, REPL.
1
Простой синтаксис.
-- Факториал
factorial 0 = 1
factorial n = n * factorial (n-1)
-- Числа Фибоначи
fib n =
let
fib1 (x1,x2) 0 = x2
fib1 (x1,x2) n = fib1 (x2,x1+x2) (n-1)
in
fib1 (0,1) n
-- Или так
fib n = fib1 (0,1) n
where
fib1 (x1,x2) 0 = x2
fib1 (x1,x2) n = fib1 (x2,x1+x2) (n-1)
-- Hellow, world
main = print "Hello, world!"
2
Ненавязчивая типизация -- вывод типов.
main = print (factorial 17)
-- правильно компилируется
main = print (factorial "17")
-- Ошибка
-- No instance for (Num [Char]) arising from a use
-- Possible fix: add an instance declaration for (N
-- In the expression: factorial "17"
-- In an equation for `it': it = factorial "17"
3
Hoogle. Тип как документация:
4
Списки -- функции для обработки
-- применить функцию ко всем элементам списка
map :: (a -> b) -> [a] -> [b]
-- вычислить агрегатную функцию, сворачивающую два
foldr :: (a -> b -> b) -> b -> [a] -> b
-- аналогично для непустых списков
foldr1 :: (a -> a -> a) -> [a] -> a
-- первый элемент списка
head :: [a] -> a
-- список без первого элемента
tail :: [a] -> [a]
5
Списки
factorial n = product [1..n]
factorial n = foldr (*) 1 [1..n]
sumList l1 l2 = zipWith (+) l1 l2
-- умножение вестора на число
scale v l = map ((*) v) l
-- умножение матриц
mmul x y =
map (l ->
foldr1 sumList (zipWith scale l y)) x
6
Списки -- DIY
-- List a - [a]
-- Nil - []
-- Cons a b - a:b
data List a = Nil | Cons a (List a)
isEmpty Nil = True
isEmpty (Cons h t) = False
headOfList Nil = error "а списочек то пуст"
headOfList (Cons h t) = h
tailOfList Nil = error "а списочек то пуст"
tailOfList (Cons h t) = t
7
Другие стандартные контейнеры
data Maybe a = Nothing | Just a
data Either a b = Left a | Right b
data (,) a b = (,) a b
8
Рекурсия и ленивость
fib = 1:1:(zitWith (+) fib (1:fib))
product (take 10000 fib) -- произведение первых 100
9
Рекурсия и ленивость -- ссылки назад
data Expr = I Int | V String | (:+) Expr Expr
infixr 7 :+
lookupVar var ((name,value):rest)
| var == name = value
| True = lookupVar var rest
evalExprs exprs = result where
result = map vareval exprs
vareval (name, expr) = (name, (eval expr))
eval (I val) = val
eval (V var) = (lookupVar var result)
eval (x :+ y) = (eval x) + (eval y)
10
Парсеры.
-- Как минимум
type Parser result = String -> result
-- Мы можем распарсить не все
type Parser result = String -> (result,String)
-- или вообще не распарсить
type Parser result = String -> Maybe (result,String)
-- ... или не однозначно
type Parser result = String -> [(result,String)]
-- получает любой символ из потока
anyChar :: Parser Char
anyChar (c:r) = [(c,r)]
anyChar [] = []
-- получает только заданный символ
char :: Char -> Parser ()
char c (s:r) | c == s = [((),r)]
char c t = []
11
Парсеры -- комбинаторы.
-- последовательность
(<&>) :: Parser a -> Parser b -> Parser (a,b)
p1 <&> p2 = s ->
[((res1,res2), rest2) |
(res1,rest1) <- p1 s,
(res2,rest2) <- p2 rest1]
-- альтернатива
(<|>) :: Parser a -> Parser a -> Parser a
p1 <|> p2 = s -> (p1 s) ++ (p2 s)
На самом деле все сложнее. Но тонкости учтены
в библиотеке Parseq!
12

More Related Content

Обработка текста на Haskell - это просто!

  • 1. Haskell это... Простой синтаксис. Статическая типизация. Но не навязчивая. Списки. Программирование без циклов и переменных. Списки, Maybe и другие алгебраические типы. Функциональное программирование, рекурсия, иммутабельность. Развитая инфраструктура, REPL. 1
  • 2. Простой синтаксис. -- Факториал factorial 0 = 1 factorial n = n * factorial (n-1) -- Числа Фибоначи fib n = let fib1 (x1,x2) 0 = x2 fib1 (x1,x2) n = fib1 (x2,x1+x2) (n-1) in fib1 (0,1) n -- Или так fib n = fib1 (0,1) n where fib1 (x1,x2) 0 = x2 fib1 (x1,x2) n = fib1 (x2,x1+x2) (n-1) -- Hellow, world main = print "Hello, world!" 2
  • 3. Ненавязчивая типизация -- вывод типов. main = print (factorial 17) -- правильно компилируется main = print (factorial "17") -- Ошибка -- No instance for (Num [Char]) arising from a use -- Possible fix: add an instance declaration for (N -- In the expression: factorial "17" -- In an equation for `it': it = factorial "17" 3
  • 4. Hoogle. Тип как документация: 4
  • 5. Списки -- функции для обработки -- применить функцию ко всем элементам списка map :: (a -> b) -> [a] -> [b] -- вычислить агрегатную функцию, сворачивающую два foldr :: (a -> b -> b) -> b -> [a] -> b -- аналогично для непустых списков foldr1 :: (a -> a -> a) -> [a] -> a -- первый элемент списка head :: [a] -> a -- список без первого элемента tail :: [a] -> [a] 5
  • 6. Списки factorial n = product [1..n] factorial n = foldr (*) 1 [1..n] sumList l1 l2 = zipWith (+) l1 l2 -- умножение вестора на число scale v l = map ((*) v) l -- умножение матриц mmul x y = map (l -> foldr1 sumList (zipWith scale l y)) x 6
  • 7. Списки -- DIY -- List a - [a] -- Nil - [] -- Cons a b - a:b data List a = Nil | Cons a (List a) isEmpty Nil = True isEmpty (Cons h t) = False headOfList Nil = error "а списочек то пуст" headOfList (Cons h t) = h tailOfList Nil = error "а списочек то пуст" tailOfList (Cons h t) = t 7
  • 8. Другие стандартные контейнеры data Maybe a = Nothing | Just a data Either a b = Left a | Right b data (,) a b = (,) a b 8
  • 9. Рекурсия и ленивость fib = 1:1:(zitWith (+) fib (1:fib)) product (take 10000 fib) -- произведение первых 100 9
  • 10. Рекурсия и ленивость -- ссылки назад data Expr = I Int | V String | (:+) Expr Expr infixr 7 :+ lookupVar var ((name,value):rest) | var == name = value | True = lookupVar var rest evalExprs exprs = result where result = map vareval exprs vareval (name, expr) = (name, (eval expr)) eval (I val) = val eval (V var) = (lookupVar var result) eval (x :+ y) = (eval x) + (eval y) 10
  • 11. Парсеры. -- Как минимум type Parser result = String -> result -- Мы можем распарсить не все type Parser result = String -> (result,String) -- или вообще не распарсить type Parser result = String -> Maybe (result,String) -- ... или не однозначно type Parser result = String -> [(result,String)] -- получает любой символ из потока anyChar :: Parser Char anyChar (c:r) = [(c,r)] anyChar [] = [] -- получает только заданный символ char :: Char -> Parser () char c (s:r) | c == s = [((),r)] char c t = [] 11
  • 12. Парсеры -- комбинаторы. -- последовательность (<&>) :: Parser a -> Parser b -> Parser (a,b) p1 <&> p2 = s -> [((res1,res2), rest2) | (res1,rest1) <- p1 s, (res2,rest2) <- p2 rest1] -- альтернатива (<|>) :: Parser a -> Parser a -> Parser a p1 <|> p2 = s -> (p1 s) ++ (p2 s) На самом деле все сложнее. Но тонкости учтены в библиотеке Parseq! 12