Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is Just in Haskell and why wouldn't this function work without it?

I have the following function that acts like an index operator:

let {
  index :: [a]->Int->Maybe a
  index [] i = error "Empty list"
  index l i = if i <= ((length l) - 1) && i >= 0 then 
      Just(l !! i) 
    else
      error "Index out of bounds"
}

Now, initially i wrote this without using Just (and i still don't understand what it is after googling):

let {
  index :: [a]->Int->Maybe a
  index [] i = error "Empty list"
  index l i = if i <= ((length l) - 1) && i >= 0 then
      (l !! i) 
    else
      error "Index out of bounds"
}

To me it the above function makes perfect sense. Because here i have a function that accepts a list of 'generic type' a and an Int which is the index and returns Maybe value of type a or throws runtime exception. However, i don't understand the bit where GHCi tells me this:

<interactive>:1:120:
Couldn't match type `a' with `Maybe a'
  `a' is a rigid type variable bound by
      the type signature for index :: [a] -> Int -> Maybe a
      at <interactive>:1:34
Expected type: [Maybe a]
  Actual type: [a]
In the first argument of `(!!)', namely `l'
In the expression: (l !! i)

Now, why is GHCi getting confused with the type of l and why is it expecting a list of type Maybe a? Finally, how does Just resolve the problem?

like image 697
badmaash Avatar asked Jan 15 '23 23:01

badmaash


2 Answers

You've specifically stated in your type annotation that your function index returns a Maybe a.

Maybe is a data type defined in Haskell thusly:

data Maybe a = Just a | Nothing

That is, it has two value constructors, Just :: a -> Maybe a and Nothing :: Maybe a. Thus, in order for you function to work correctly, it must return either a Just a or a Nothing.

This also means that you should be able to remove your error statements with a bit of thought and encode the actual error in the Nothing (ie. we were out of bounds, no element here!) and only return a result Just a if it makes sense.

like image 174
Sarah Avatar answered Jan 24 '23 01:01

Sarah


You told GHC the return type of index as Maybe a. That means that (l !! i) (a value returned by index) must be of type Maybe a.

Since (l !! i) is selecting a single element out of the list l, that means l must be of type [Maybe a] in order for one of its elements to be Maybe a.

But l is the first argument to index, which you have also told GHC is typed [a].

That's exactly your error. GHC is trying to compile an index into a [Maybe a] to get a Maybe a, but instead it's found the thing being indexed is a [a].

The reason Just fixes this, is that Just is of type a -> Maybe a. So when you say Just (l !! i), GHC now sees you indexing a [a] to get an a, and then applying Just to that which results in a Maybe a, as expected.

like image 37
Ben Avatar answered Jan 24 '23 00:01

Ben