deniok: (typed lambda)
[personal profile] deniok
На 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]


Date: 2009-10-18 10:26 am (UTC)
From: [identity profile] deni-ok.livejournal.com
Ну сама по себе автоматизация этого - дело нехитрое (см. ниже по треду). Вот только насколько это полезно оптимизатору...

Date: 2009-10-18 10:50 am (UTC)
From: [identity profile] helvegr.livejournal.com
По идее, трансформация (. f) . g в g(x, f z) убирает ненужную partial application. Про @unpl я знаю, интересно было, работает ли это из коробки.

На моём маленьком примере работает:

Исходник:

g :: (a -> b) -> [a] -> [b]
g f l = map f (tail l)

h :: (a -> b) -> [a] -> [b]
h = (. tail) . map

Core:

h :: forall a_afx b_afy.
          (a_afx -> b_afy) -> [a_afx] -> [b_afy]

h =
  \ (@ a_afP)
    (@ b_afQ)
    (x_ayH :: a_afP -> b_afQ)
    (eta_syZ :: [a_afP]) ->
    map @ a_afP @ b_afQ x_ayH (tail @ a_afP eta_syZ)

g :: forall a_afA b_afB.
          (a_afA -> b_afB) -> [a_afA] -> [b_afB]
      
g =
  \ (@ a_agK)
    (@ b_agL)
    (f_afD :: a_agK -> b_agL)
    (l_afF :: [a_agK]) ->
    map @ a_agK @ b_agL f_afD (tail @ a_agK l_afF)


Как можно видеть, Core-представление обоих функций идентично.

Date: 2009-10-18 01:36 pm (UTC)
From: [identity profile] helvegr.livejournal.com
s/обоих/обеих/

Profile

deniok: (Default)
deniok

February 2022

S M T W T F S
  12345
6789101112
13141516171819
20212223 242526
2728     

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 17th, 2025 02:20 am
Powered by Dreamwidth Studios