List Comprehension vs do-notation
Запись от Mysterious Light размещена 19.05.2016 в 21:21
Показов 2077
Комментарии 0
|
Предисловие В функциональных языках (Haskell из семейства ML, C#, Python и подобных) есть так называемый list comprehension (LC). Это способ записи списковых выражений, порождённых другими списками. Например, [ div x y | x <- [1995..2000], y <- [1..floor(sqrt(x))], mod x y == 0 ] возвратит список чисел, которые являются делителями какого-то x из интервала из одного интервала, причём большие Здесь и далее используется Haskell-подобная запись. Или, скажем, [ (x,y) | x <- a, y <- b ] вовзратит декартово произведение списков a и b. Или [ (x1,y2) | (x1,x2) <- a, (y1,y2) <- b, x2==y1 ] возвратит то, что в реляционной алгебре называется JOIN двух таблиц a и b. Любое выражение LC можно переписать в виде аппликативного выражения с комбинаторами map, filter и concat. Например, [ (x1,y2) | (x1,x2) <- a, (y1,y2) <- b, x2==y1 ] = concat (map (\(x1,x2) -> map (\(y1,y2) -> (x1,y2)) (filter (\(y1,y2) -> x2==y1) b)) a) где (\x -> ...x...) означает анонимную функцию (лямбда-выражение) с формальным аргументом x и телом ...x... Кроме этого, в Haskell имеется do-нотация, суть которой в том, чтобы удобно записывать выражения с монадами — объектами, которые в некотором смысле несут некоторое значение плюс ещё что-то. Монады — это один из возможных способов работать с заведомо нечистыми операциями (ввод/вывод, управление памятью) в чистом функциональном языке. Пример do-выражения
Оказалось, использовать do-нотацию можно по отношению к любому типу, который реализует неколько основных функций, в частности,
a и b — произвольные типа, функции map, return и join являются параметрически-полиморфными (дженериками/generic). Так вот, если положить fmap=map, return x = [x], join=concat, то тип списка m a = [a] окажется монадой. В частности, можно писать
Суть вопроса Если внимательно посмотреть, станет видно, что LC и do крайне похожи. Особое сходноство достигается, если потребовать, чтобы монада m имела объект mzero :: m a для произвольного типа a такой, что do{...; mzero; ...} = mzero. Для монады-списка это пустой список []. Тогда можно определить функцию guard, которая в зависимости от условия-аргумента либо выбрасывает ноль, либо возвращает один (пустой, бессодержательный) объект.
| ||||||||||||||||||||||||||
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии


