Почему Haskell - хороший выбор для обработки текста.
1 of 12
Download to read offline
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
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
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