1

I was trying to understand applicative and how i can use it as a cartesian product between K functions and N parameters ,and i can't comprehend why i can't do the following:

[Just (+1),Just (+2)] <*> [Just 1 ,Just 2] renders

Error

* 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]

I do not understand since from the definition it is supposed to take the functions out of the context, take the values and apply all combinations.

I have also tried :

:t [pure (+1),pure (+2)] <*> [Just 1 ,Just 2] :: Num a => [a -> a] and i can't understand why the resulting type is not a list of values (and not a->a) ,since all operators expect only one argument,and i am already supplying that.

Can someone shed some light?

  • 1
    The context (in this case []) does not contain functions. It contains Maybes. So trying to apply the functions in the context is a type error. This is why the error says that it expected a function but actually got a Maybe instead. Try [(+1), (+2)] <*> [1,2] instead. – Rein Henrichs Apr 20 at 21:02
  • 3
    You here have two levels of functors: a list, and a Maybe. – Willem Van Onsem Apr 20 at 21:04
  • 1
    Are you deliberately trying to compose the two applicatives [] and Maybe? If so, then this won't work by default because GHC doesn't understand you're working with a composition. You need to make a new type for the composition, either with Compose or "by hand" with something like newtype MaybeList a = [Maybe a] (and then supply your own Applicative instance for MaybeList). – Robin Zigmond Apr 20 at 21:15
13

There are two applicative layers involved here ([] and Maybe), so (<*>) itself must be applied applicatively:

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

This use case is captured by the Compose newtype. Nesting any two applicative functors gives rise to another applicative:

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]

.

  • Can you elaborate how does <$> work in this case? You have a f g (k::a->a) and f g a .So you have two functors f and g. You have an a and a a->a.I do not understand how you unwrap the functors using (<*>) <$> in the first case. – Bercovici Adrian Apr 21 at 6:03
  • 1
    @BercoviciAdrian In this example, the first list is [Maybe (Integer -> Integer)]. (<$>) maps through the list layer (but not the Maybe one). We have (<*>) :: Applicative f => f (a -> b) -> (f a -> f b), so the first (<*>) specialises to Maybe (Integer -> Integer) -> (Maybe Integer -> Maybe Integer) -- we're (partially) applying (<*>) to the Maybevalues in the first list. That being so, (<*>) <$> [Just (+1),Just (+2)] ends up being [Maybe Integer -> Maybe Integer], which is what you need to use with the second (<*>) (which, like the (<$>), uses the list Applicative). – duplode Apr 21 at 6:46
  • But i do not understand then why you can't unwrap without using the <$>.I mean (<*>) [Just (+1)] would mean you bind the first argument , and then you can just supply the value one. Your generic argument becomes a=Maybe a – Bercovici Adrian Apr 21 at 6:59
  • 1
    @BercoviciAdrian For that to work, Just (+1) would have to be a function, but it isn't one (it is a Maybe-value that holds a function). (<*>) can only work through one applicative layer; that's why we need a second (<*>). (The alternative is using Compose to handle the two layers as one.) – duplode Apr 21 at 7:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.