Haskell Language
Список рекомендаций
Поиск…
Основные сведения о списках
В Haskell есть списки , которые очень похожи на набор понятий в математике и аналогичных реализациях на императивных языках, таких как Python и JavaScript. В большинстве своих основных понятий списков принимают следующую форму.
[ x | x <- someList ]
Например
[ x | x <- [1..4] ] -- [1,2,3,4]
Функции могут быть непосредственно применены к x:
[ f x | x <- someList ]
Это эквивалентно:
map f someList
Пример:
[ x+1 | x <- [1..4]] -- [2,3,4,5]
Шаблоны выражений генератора
Однако x
в выражении генератора не просто переменна, но может быть любым шаблоном. В случае несоответствия шаблона сгенерированный элемент пропускается, а обработка списка продолжается следующим элементом, действуя, как фильтр:
[x | Just x <- [Just 1, Nothing, Just 3]] -- [1, 3]
Генератор с переменной x
в своем шаблоне создает новую область, содержащую все выражения справа, где x
определяется как сгенерированный элемент.
Это означает, что охранники могут быть закодированы как
[ x | x <- [1..4], even x] ==
[ x | x <- [1..4], () <- [() | even x]] ==
[ x | x <- [1..4], () <- if even x then [()] else []]
гвардия
Еще одна особенность списков - это защита, которая также действует как фильтры. Охранники являются булевыми выражениями и отображаются в правой части панели в понимании списка.
Их основное использование
[x | p x] === if p x then [x] else []
Любая переменная, используемая в охраннике, должна появляться слева в понимании или иначе находиться в области видимости. Так,
[ f x | x <- list, pred1 x y, pred2 x] -- `y` must be defined in outer scope
что эквивалентно
map f (filter pred2 (filter (\x -> pred1 x y) list)) -- or,
-- ($ list) (filter (`pred1` y) >>> filter pred2 >>> map f)
-- list >>= (\x-> [x | pred1 x y]) >>= (\x-> [x | pred2 x]) >>= (\x -> [f x])
(оператор >>=
является infixl 1
, т. е. сопоставляет (заключен в скобки) влево). Примеры:
[ x | x <- [1..4], even x] -- [2,4]
[ x^2 + 1 | x <- [1..100], even x ] -- map (\x -> x^2 + 1) (filter even [1..100])
Вложенные генераторы
В списках можно также нарисовать элементы из нескольких списков, и в этом случае результатом будет список всех возможных сочетаний двух элементов, как если бы два списка были обработаны вложенным образом. Например,
[ (a,b) | a <- [1,2,3], b <- ['a','b'] ]
-- [(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]
Параллельное понимание
С расширением языка Parallel List понимает ,
[(x,y) | x <- xs | y <- ys]
эквивалентно
zip xs ys
Пример:
[(x,y) | x <- [1,2,3] | y <- [10,20]]
-- [(1,10),(2,20)]
Локальные привязки
В списках можно ввести локальные привязки для переменных для хранения некоторых промежуточных значений:
[(x,y) | x <- [1..4], let y=x*x+1, even y] -- [(1,2),(3,10)]
Тот же эффект может быть достигнут с помощью трюка,
[(x,y) | x <- [1..4], y <- [x*x+1], even y] -- [(1,2),(3,10)]
Способы let
в список являются рекурсивными, как обычно. Но привязки генераторов нет, что позволяет затенять :
[x | x <- [1..4], x <- [x*x+1], even x] -- [2,10]
Обозначать
Любой список понимание может быть соответствующим образом закодированы список монады do
запись .
[f x | x <- xs] f <$> xs do { x <- xs ; return (f x) }
[f x | f <- fs, x <- xs] fs <*> xs do { f <- fs ; x <- xs ; return (f x) }
[y | x <- xs, y <- f x] f =<< xs do { x <- xs ; y <- f x ; return y }
Охранники могут обрабатываться с помощью Control.Monad.guard
:
[x | x <- xs, even x] do { x <- xs ; guard (even x) ; return x }