DEV Community

Cover image for Lifting const
Christian Gill
Christian Gill

Posted on

Lifting const

Yesterday I shared this gist:

And I planned to expand on it today based on some assumptions I had.

By playing around in GHCi I found out that my assumption was wrong.

you are wrong meme

So I did a bit of digging, by digging I mean Hoogling the functions and checking their sources in Hackage, to understand why.

I found some interesting things.

Let's check again how the operator (<*) works.

(<*) :: Applicative f => f a -> f b -> f a
Enter fullscreen mode Exit fullscreen mode

As it is always the case in Haskell, the signature says a lot. It looks like it takes two applicatives and returns the first one.

Just 1 <* Just 2 -- Just 1
Enter fullscreen mode Exit fullscreen mode

And yes, that's right. But there's more...

It does not only return the first one discarting the second. Instead it "runs" both and returns the first one. How do we know it "runs" both? Because the semantic of such applicative (in this case Maybe) are respected:

Nothing <* Just 1  -- Nothing
Just 1  <* Nothing -- Nothing
Enter fullscreen mode Exit fullscreen mode

And that is the difference with const.

Just 1  `const` Just 2  -- Just 1
Just 1  `const` Nothing -- Just 1
Nothing `const` Just 1  -- Nothing
Enter fullscreen mode Exit fullscreen mode

When I said that (<*) is the "lifted" version of const I didn't mean lifted in the Haskell sence, I meant lifted as in the function was used in the context of an applicative. Well I guess that's kind of what lifted means, so let's try again. What I meant is that the signature was "the same" but in the applicative context (same semantics, always returning the first argument and discarting the second).

Turns out, (<*) is actually the "lifted" version of const (in the Haskell sense). Oh, and that's exactly the implementation in base.

class Functor f => Applicative f where
    -- ...

    -- | Sequence actions, discarding the value of the second argument.
    (<*) :: f a -> f b -> f a
    (<*) = liftA2 const
Enter fullscreen mode Exit fullscreen mode
See source in Hackage

So what I was wrong about? 🤔

I assumed that if you lifted const it would still behave as the good ol' const.

constA = liftA2 const

Just 1  `constA` Just 2  -- Just 1
Just 1  `constA` Nothing -- Just 1
Nothing `constA` Just 1  -- Nothing
Enter fullscreen mode Exit fullscreen mode

Well, as we saw already, it doesn't. As I said it respects the semantics of the applicative.

constA = liftA2 const

Just 1  `constA` Just 2  -- Just 1
Just 1  `constA` Nothing -- Nothing
Nothing `constA` Just 1  -- Nothing
Enter fullscreen mode Exit fullscreen mode

Because that is the whole point of liftA2.

* to be continued (whit a deeper look into liftA2).

P.S. Yeah I used a "lifting" 🏋️ picture in a post about lifting. Sorry.

Top comments (1)

Collapse
 
riccardoodone profile image
Riccardo Odone

The series is awesome! Keep it up!