Как ‹*› работает с функцией Applicative?

Я пытаюсь понять с помощью лямбда-исчисления, почему результат функции следующего кода

(,) <$> (+1) <*> (+1)

имеет тип Num a => a -> (a, a) вместо Num a => a -> a -> (a, a)

Это то, что у меня есть, я делаю что-то ужасно неправильно или ‹*> просто подключен таким образом?

( \x, y -> (,) x y ) <$> ( \x -> x + 1 ) <*> ( \x -> x + 1 )

-- fmap applies first

(\x y -> (,) ((+1) x) y ) <*> ( \x -> x + 1 ) -- substituted the lambda with (+1) for better clarity

-- then goes apply

( \x y -> (,) ((+1) x) ((+1) y) )

как унифицируются параметры лямбды и в какой момент?


person D. Amoroso    schedule 20.12.2016    source источник
comment
По определению в этом аппликативе f <*> g = \x -> f x (g x). Обратите внимание, что здесь, если f является двоичным, результатом является унарная функция. Ваш последний результат должен быть \x -> (,) ((+1) x) ((+1) x)   -  person chi    schedule 20.12.2016


Ответы (1)


Давайте посмотрим типы в вашем примере:

(,)            <$> (+1)            <*> (+1)
^                  ^                   ^
|                  |                   |
a -> b -> (a, b)   Num a => a -> a     Num a => a -> a

Правая часть (<$>) и правая/левая часть (<*>) должны быть аппликативным функтором. Ваш функтор — Num a => (->) a (читатель монад).

Итак, какой тип будет после (<$>) приложения (Псевдокод):

a -> b -> (a, b) <$> Num a => (->) a a ==> Num a => (->) a (b -> (a, b))

После (<*>) (псевдокод):

Num a => (->) a (b -> (a, b)) <*> Num a => (->) a a ==> Num a => (->) a (a, a)

Но Num a => (->) a (a, a) эквивалентно Num a => a -> (a, a).


Как написал @chi в голове, реализация (<*>) для типа (->) r такова:

(<*>) :: (->) r (a -> b) -> (->) r a -> (->) r b
f <*> g = \r -> f r (g r)

А при подаче заявки вы получите:

(\x y -> (,) x y) <$> (\r -> r + 1) <*> (\r -> r + 1) =
= (\r y -> (,) (r + 1) y) <*> (\r -> r + 1) =
= \r -> (,) (r + 1) (r + 1)
person freestyle    schedule 20.12.2016