Преобразование функции в Haskell для обозначения свободной нотации - PullRequest
0 голосов
/ 02 ноября 2018

У меня есть функция в haskell на бумаге в качестве примера:

function2 a b c = (a * b) + c 

и мне нужно написать пример в нотации без точек. Я очень плохо работаю со стилем без точек, потому что нахожу это действительно запутанным без надлежащего руководства, поэтому я попробовал:

function2 a b c = (a * b) + c
function2 a b c = ((*) a b) + c #operator sectioning
function2 a b c = (+) ((*) a b)c #operator sectioning once more
#I'm stuck here now

Я не был уверен, что будет дальше, так как это был предел, который я мог придумать для этого примера. Был бы признателен за помощь в этом.

- Второй пример:

function3 a b = a `div` (g b)
function3 a b = `div` a (g b) --operator sectioning
function3 a b = (`div` a) (g b) --parentheses
function3 a b = ((`div` a g).)b --B combinator
function3 a   = ((`div` a g).) --eta conversion
function3 a   = ((.)(`div` a g)) --operator sectioning
function3 a   = ((.)flip(`div` g a))
function3 a   = ((.)flip(`div` g).a) --B combinator
function3     = ((.)flip(`div` g)) --eta conversion (complete)

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Мы можем продолжить с:

function2 a b = (+) ((*) a b)     [eta-reduction]
function2 a = (+) . (*) a         [using a dot, to eliminate the b]
function2 = ((.) . (.)) (+) (*)   ["blackbird" operator to pass two parameters]

Здесь «оператор черного дрозда» представляет собой комбинацию из трех (.) :: (b -> c) -> (a -> b) -> a -> c операторов. Функционально эквивалентно:

((.) . (.)) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
((.) . (.)) f g x y = f (g x y)

см. Здесь вывод .

0 голосов
/ 02 ноября 2018

Вы можете применить комбинатор B (т.е. (f . g) x = f (g x)) там:

function2 a b c = (a * b) + c
function2 a b c = ((*) a b) + c    -- operator sectioning
function2 a b c = (+) ((*) a b) c  -- operator sectioning once more
      = (+) (((*) a) b) c          -- explicit parentheses
      = ((+) . ((*) a)) b c        -- B combinator
      = ((.) (+) ((*) a)) b c      -- operator sectioning 
      = ((.) (+) . (*)) a b c      -- B combinator

Действительно, типы одинаковы:

> :t let function2 a b c = (a * b) + c in function2
let function2 a b c = (a * b) + c in function2
  :: Num a => a -> a -> a -> a

> :t ((.) (+) . (*))
((.) (+) . (*)) :: Num b => b -> b -> b -> b

Мы работаем, выводя аргументы один за другим в правильном порядке, чтобы в итоге получить

function2 a b c = (......) a b c

так что eta-сжатие может быть применено, чтобы избавиться от явных аргументов,

function2       = (......) 

Наши инструменты , которые мы можем применить в обоих направлениях ,

S a b c  =  (a c) (b c)  =  (a <*> b) c
K a b    =  a            =  const a b
I a      =  a            =  id a
B a b c  =  a (b c)      =  (a . b) c
C a b c  =  a c b        =  flip a b c
W a b    =  a b b        =  join a b
U a      =  a a          -- not in Haskell: `join id` has no type

Там также (f =<< g) x = f (g x) x = join (f . g) x.

Еще несколько полезных шаблонов, которые появляются, когда мы некоторое время работаем с pointfree:

((f .) .) g x y = f (g x y)
(((f .) .) .) g x y z = f (g x y z)
.....
((. g) . f) x y = f x (g y)
((. g) . f . h) x y = f (h x) (g y)

(обновление.) Во втором примере рядом с началом есть ошибка, после которой все следующие шаги становятся недействительными:

function3 a b = a `div` (g b)
function3 a b = -- `div` a (g b)     -- wrong syntax, you meant
                div a (g b)
function3 a b = -- (`div` a) (g b)   -- wrong; it is
                (a `div`) (g b) --operator sectioning
function3 a b = ((a `div`) . g) b --B combinator
function3 a   = (div a . g) --eta conversion; back with plain syntax
function3 a   = (.) (div a) g --operator sectioning
function3 a   = flip (.) g (div a) --definition of flip
function3 a   = (flip (.) g . div) a --B combinator
function3     = (flip (.) g . div) --eta conversion
              = (.) (flip (.) g) div  --operator section

Так что да, некоторые шаги были в правильном направлении.

...