softshipper
softshipper

Reputation: 34099

Why can I use pure function to convert to applicative

I have following type definition:

  data Hello a b =  Hi a
                  | Sali b
                  deriving (Show, Eq) 

and it isn't an instance of Applicative but I can still use pure to convert it to Applicative why?

*ExercisesTraversable Data.Monoid Control.Applicative> :t pure $ Hi 34
pure $ Hi 34 :: (Num a, Applicative f) => f (Hello a b)

*ExercisesTraversable Data.Monoid Control.Applicative> pure $ Hi 34
Hi 34

And when I try:

*ExercisesTraversable Data.Monoid Control.Applicative> (Sali (*2)) <*> (Sali 4)

<interactive>:23:1: error:
    * Non type-variable argument
        in the constraint: Applicative (Hello a)
      (Use FlexibleContexts to permit this)
    * When checking the inferred type
        it :: forall b a. (Num b, Applicative (Hello a)) => Hello a b

that is clear, because it isn't an Applicative instance.

Upvotes: 1

Views: 106

Answers (2)

chepner
chepner

Reputation: 532153

Since you aren't specifying any Applicative type in particular, ghci is defaulting to IO, i.e. pure $ Hi 34 returns a value of type Num a => IO (Hello a b). That is, Hello a b isn't the f in a -> f a, it's the a.

You can see more explicitly that Hello a b is the typed wrapped by an arbitrary Applicative by specifying various Applicative functors for the value:

Prelude> (pure $ Hi 34) :: Either String (Hello Int b)
Right (Hi 34)
Prelude> (pure $ Hi 34) :: Maybe (Hello Int b)
Just (Hi 34)
Prelude> (pure $ Hi 34) :: [Hello Int b]
[Hi 34]

Upvotes: 6

arrowd
arrowd

Reputation: 34411

When you call pure x it is not x that should be Applicative, but the whole pure x expression. Take a look at pure type:

Prelude> :t pure
pure :: Applicative f => a -> f a

See? You pass it a, but Applicative constraint is on f, and that f only appears in the result. So, it is the result that should be of class Applicative, and as @chepner said, GHCi prompt defaults to IO, which is Applicative.

Upvotes: 4

Related Questions