Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

From the docs, Data.Maybe:

The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing).

If you are looking for a type Maybe Int then your function will return either Nothing, or Just Int.

It is a simple kind of error monad, where all errors are represented by Nothing.

Essentially if Nothing is returned then something has happened which has resulted in the function not being able to find a result. The Just qualifier allows you to operate on these Maybe types.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top