Как <*> работает с Function 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) )
как унифицировать параметры лямбды и в какой момент?
1 ответ
Решение
Давайте посмотрим типы в вашем примере:
(,) <$> (+1) <*> (+1)
^ ^ ^
| | |
a -> b -> (a, b) Num a => a -> a Num a => a -> a
Rhs of (<$>)
и Rhs/Lhs из (<*>)
должен быть Аппликативным Функтором. Ваш функтор 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)