Декартово произведение не работает для аппликативного

Я пытался понять аппликатив и то, как я могу использовать его как декартово произведение между K функциями и N параметрами, и я не могу понять, почему я не могу сделать следующее:

[Just (+1),Just (+2)] <*> [Just 1 ,Just 2] визуализирует

Ошибка

* Couldn't match expected type `Maybe Integer -> b'
                  with actual type `Maybe (Integer -> Integer)'
    * Possible cause: `Just' is applied to too many arguments      In the expression: Just (+ 1)      In the first argument of `(<*>)', namely `[Just (+ 1), Just (+ 2)]'
      In the expression: [Just (+ 1), Just (+ 2)] <*> [Just 1, Just 2]

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

Я также пробовал:

:t [pure (+1),pure (+2)] <*> [Just 1 ,Just 2] :: Num a => [a -> a] и я не могу понять, почему результирующий тип не является списком значений (и не a->a), так как все операторы ожидают только один аргумент, а я его уже предоставляю.

Может кто-нибудь пролить свет?


person Bercovici Adrian    schedule 20.04.2019    source источник
comment
Контекст (в данном случае []) не содержит функций. Он содержит Maybes. Таким образом, попытка применить функции в контексте является ошибкой типа. Вот почему ошибка говорит, что она ожидала функцию, но вместо этого получила Maybe. Вместо этого попробуйте [(+1), (+2)] <*> [1,2].   -  person Rein Henrichs    schedule 21.04.2019
comment
Здесь у вас есть два уровня функторов: список и Maybe.   -  person Willem Van Onsem    schedule 21.04.2019
comment
Вы намеренно пытаетесь составить два аппликатива [] и Maybe? Если это так, то это не будет работать по умолчанию, потому что GHC не понимает, что вы работаете с композицией. Вам нужно сделать новый тип для композиции, либо с помощью Составить или вручную с помощью чего-то вроде newtype MaybeList a = [Maybe a] (а затем указать свой собственный экземпляр Applicative для MaybeList).   -  person Robin Zigmond    schedule 21.04.2019


Ответы (1)


Здесь задействованы два аппликативных слоя ([] и Maybe), поэтому сам (<*>) должен применяться аппликативно:

GHCi> (<*>) <$> [Just (+1),Just (+2)] <*> [Just 1 ,Just 2]
[Just 2,Just 3,Just 3,Just 4]

Этот вариант использования захвачен Compose newtype. Вложение любых двух аппликативных функторов приводит к возникновению другого аппликативного:

GHCi> import Data.Functor.Compose
GHCi> Compose [Just (+1),Just (+2)] <*> Compose [Just 1 ,Just 2]
Compose [Just 2,Just 3,Just 3,Just 4]

.

person duplode    schedule 20.04.2019
comment
Можете ли вы уточнить, как <$> работает в этом случае? У вас есть f g (k::a->a) и f g a. Итак, у вас есть два функтора f и g. У вас есть a и a->a. Я не понимаю, как вы разворачиваете функторы, используя (<*>) <$> в первом случае. - person Bercovici Adrian; 21.04.2019
comment
@BercoviciAdrian В этом примере первый список — [Maybe (Integer -> Integer)]. (<$>) отображается через слой списка (но не Maybe). У нас есть (<*>) :: Applicative f => f (a -> b) -> (f a -> f b), поэтому первый (<*>) специализируется на Maybe (Integer -> Integer) -> (Maybe Integer -> Maybe Integer) — мы (частично) применяем (<*>) к Maybeзначениям в первом списке. Таким образом, (<*>) <$> [Just (+1),Just (+2)] становится [Maybe Integer -> Maybe Integer], что вам и нужно использовать со вторым (<*>) (который, как и (<$>), использует список Applicative). - person duplode; 21.04.2019
comment
Но тогда я не понимаю, почему вы не можете развернуть без использования <$>. Я имею в виду, что (<*>) [Just (+1)] будет означать, что вы связываете первый аргумент, а затем вы можете просто указать значение one. Ваш общий аргумент становится a=Maybe a - person Bercovici Adrian; 21.04.2019
comment
@BercoviciAdrian Чтобы это работало, Just (+1) должна быть функцией, но это не так (это значение Maybe, которое содержит функцию). (<*>) может работать только через один аппликативный слой; вот почему нам нужен второй (<*>). (Альтернативой является использование Compose для обработки двух слоев как одного.) - person duplode; 21.04.2019