deniok: (typed lambda)
deniok ([personal profile] deniok) wrote2009-10-16 05:09 pm
Entry tags:

Как нам посечь композицию: point-free на стероидах

На RSDN nikov последнее время пишет в point-free стиле на стероидах, используя конструкции имеющие "довольно ясный интуитивный смысл (c)". Типа
fpower = (appEndo.).(mconcat.).(.Endo).replicate
Поскольку я когда-то взвалил на себя ношу по несению point-free стиля в массы, придется писать мини-туториал.



Конструкция (. f) . g
\f g -> (. f) . g :: (d -> b) -> (a -> b -> c) -> (a -> d -> c)
Конструкция (. f) . g порождает функцию, эквивалентную g, только её второй аргумент вместо явной передачи заменен на результат вызова f.
g         :: a -> b -> c
f         :: d -> b
тогда
(. f) . g :: a -> d -> c
Диаграммой:
     d
    f|
     v
a -> b -> c
     g
В виде вызовов (с типами):
(g x::a (f z::d)::b)::c
Примеры:
-- перед отображением берем хвост списка
(. tail) . map
-- перед зиповкой увеличиваем элементы первого списка на 1
(. map succ) . zipWith
--перед свёрткой фильтруем список
(. filter (>3)) . foldr1
-- point-free определение replicate
(. repeat) . take


Конструкция (f .) . g
\f g -> (f .) . g :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
Конструкция (f .) . g порождает функцию, эквивалентную g, только её результат обрабатывается затем f.
g         :: a -> b -> c
f         :: d -> b
тогда
(f .) . g :: a -> b -> d
Диаграммой:
     g
a -> b -> c
          |f
          v
          d
В виде вызовов (с типами):
(f (g x::a y::b)::c)::d
Примеры:
-- point-free определение takeWhile
(fst .) . span
-- point-free определение mapM
(sequence .) . map
-- возвращает 0 при неудачном поиске
(fromMaybe 0 .) . find



Конструкция g . (f .)
\f g -> g . (f .) :: (d -> b) -> ((a -> b) -> c) -> ((a -> d) -> c)
Конструкция g . (f .) порождает функцию, эквивалентную g, только вместо ее функционального аргумента передается композиция f и нового функционального аргумента.
g         :: (a -> b) -> c
f         ::  d -> b
тогда
g . (f .) :: (a -> d) -> c
Диаграммой:
      d
     f|
      v
(a -> b) -> c
     g
В виде вызовов (с типами):
(g (f::d->b . h::a->d)::a->b)::c
Пример:
-- при отображении к передаваемой функции 
-- спереди прикомпозируется преобразование digitToInt
map . (digitToInt .)
-- при проверке видно, что succ вызывается 
-- до преобразования к Int (вылет на digitToInt 'G')
> (map . (digitToInt .)) succ "ABCDE"
[11,12,13,14,15]
> (map . (digitToInt .)) succ "ABCDEF"
[11,12,13,14,15,*** Exception: Char.digitToInt: not a digit 'G'



Конструкция g . (. f)
\f g -> g . (. f) :: (a -> d) -> ((a -> b) -> c) -> ((d -> b) -> c)
Конструкция g . (. f) порождает функцию, эквивалентную g, только вместо ее функционального аргумента передается композиция нового функционального аргумента и f.
g         :: (a -> b) -> c
f         ::  a -> d
тогда
g . (. f) :: (d -> b) -> c
Диаграммой:
     g
(a -> b) -> c
 |f
 v
 d
В виде вызовов (с типами):
(g (h::d->b . f::a->d)::a->b)::c
Пример:
-- при отображении к передаваемой функции 
-- сзади прикомпозируется преобразование digitToInt
map . (. digitToInt)
-- при проверке видно, что succ вызывается 
-- после преобразования к Int (нет вылета в отличие от прошлого примера)
> (map . (.digitToInt)) succ "ABCDE"
[11,12,13,14,15]
> (map . (.digitToInt)) succ "ABCDEF"
[11,12,13,14,15,16]


[identity profile] ivan-gandhi.livejournal.com 2009-10-16 05:09 pm (UTC)(link)
Фигасе докуда прогресс дошел.

[identity profile] deni-ok.livejournal.com 2009-10-16 05:17 pm (UTC)(link)
Большинство людей придерживается той мысли (вероятно довольно разумной), что такой код тяжело читать, при всей его экстраординарной лаконичности.

А мне нравится :)

[identity profile] nponeccop.livejournal.com 2009-10-16 11:27 pm (UTC)(link)
Maintenance - это не только чтение, но и модификация. Если кто помнит, первые версии HN0 были поинтфри. Так я отказался от затеи, потому что было очень сложно модифицировать. Малые изменения в требованиях приводили к радикальному переписыванию.

[identity profile] ivan-gandhi.livejournal.com 2009-10-18 06:41 am (UTC)(link)
Как раз лишнее выкинуто - и всегда можно подставить, мысленно прогоняя исполнение.