Trouble understanding Haskell function
Asked Answered
S

4

6

I'm having trouble understanding why the following code correctly compiles:

f :: a -> Maybe a
f = return Just 3

return Just has a type of Monad m => m (a -> Maybe a) so I'm not sure why passing in an Int unwraps the monad.

You can even get a little crazy with it:

f :: a -> Maybe a
f = return Just (Just . Just . Just . Just)

Can someone explain what exactly is going on here?

Sillabub answered 7/5, 2024 at 15:19 Comment(0)
G
7

You're using return from the reader monad (->) Int, which is defined as const. In this case return Just has type Int -> a -> Maybe a.

f = return Just 3
  = const Just 3
  = Just
Gilder answered 7/5, 2024 at 15:28 Comment(0)
L
4

This is somewhat confusing because you probably have only seen type class instances for data/newtype types, but they can be defined over any Haskell type, so here's what's happening here:

There's no "unwrapping" happening here. There simply is a monad instance for (->) r which you might know as Reader.

You can check that this exists by typing :i (->) in ghci:

ghci> :i (->)
-- some stuff which isn't relevant here, and then:
instance Applicative ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Monad ((->) r) -- Defined in ‘GHC.Base’

Instantiating this for our case:

return :: a -> ((->) r) a -- which is just a -> r -> a
-- 
Just :: x -> Maybe x
-- ==>
return Just :: r -> (x -> Maybe x) -- after substituting a = x -> Maybe x
-- ==>
return Just 3 :: x -> Maybe x -- after substituting r = Int

so return Just 3 just becomes a fancy way to write Just. Since we're not using r you can pass whatever you like for it, even undefined.

Lewert answered 7/5, 2024 at 15:28 Comment(0)
N
2

return Just has a type of Monad m => m (a -> Maybe a)

Correct, and applying something to it, e.g., return Just 3 – which is equivalent to (return Just) 3 – implies that return Just must be a function and therefore its type, m (a -> Maybe a), must correspond to a function type. So, the Monad instance for (->) r is used.

The TypeApplications extension can help to understand what's happening here:

ghci> :set -XTypeApplications
ghci> :type return @((->) _)
return @((->) _) :: a -> w -> a

Essentially, the particular type of return for the Monad instance you are using is:

return :: a -> w -> a

When passing Just to return as in return Just – since you are applying the function – the first parameter of the return type goes away, and its type is inferred to be a -> Maybe a because that is the type of Just:

ghci> :type return @((->) _) Just
return @((->) _) Just :: w -> (a -> Maybe a)

So, the particular type of return Just for the monad of functions is:

return Just :: w -> (a -> Maybe a)

Finally, passing 3 results in return Just 3 :: a -> Maybe a.

Nightie answered 7/5, 2024 at 17:28 Comment(1)
You can also ask for the type of the return within the whole expression, with my handy Forall What? trick: let { it :: forall what. _; it = (return :: what) Just 3 } in it will tell you that this instance of return has the type (a -> Maybe a) -> Integer -> a -> Maybe a, where the Integer comes from defaulting.Leilanileininger
G
1

so I'm not sure why passing in an Int unwraps the monad.

You perform function application, so the only Monad instance that is fit, is instance Monad (->) a [Haskell-src]:

-- | @since 2.01
instance Functor ((->) r) where
    fmap = (.)

-- | @since 2.01
instance Applicative ((->) r) where
    pure = const
    (<*>) f g x = f x (g x)
    liftA2 q f g x = q (f x) (g x)

-- | @since 2.01
instance Monad ((->) r) where
    f >>= k = \ r -> k (f r) r

Thus thus means that return uses the pure function, and pure is implemented as const.

So the m in Monad m => m (a -> Maybe a) will be (->) b, and thus boil down to b -> (a -> Maybe a). The implementation of return is then const, so:

f = return Just 3
  = const Just 3
  = (\x -> Just) 3
  = Just

It thus essentially ignores the parameter, and returns the function wrapped in the monad.

Golding answered 8/5, 2024 at 7:30 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.