Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define a default return value to Haskell function

I'm learning Haskell and I'm doing the H99 (99 Haskell Problems). I'm working on the first set of problems and the topic is lists. The exercise I'm working on asks to return the last element of a list. And I did it in three different ways:

-- first approach using conditions
myLast :: [Integer] -> Integer
myLast l =
    if null l then
        -1
    else
        l !! ((length l) - 1)
-- second approach using guards
myLast :: [Integer] -> Integer
myLast l
    | null l = -1
    | otherwise = l !! ((length l) - 1)
-- third approach using last function
myLast :: [Integer] -> Integer
myLast l
    | null l = -1
    | otherwise = last l

Then I thought "Despite the fact that a list only accepts elements of a unique type, can I declare the list with two possible types?". Apparently I can:

myLast :: [Either Integer String] -> Either Integer String

But things get messy when I check if the list is empty. What should I return?

myLast :: [Either Integer String] -> Either Integer String
myLast l =
    if null l then
        -- what should I return?
    else
        l !! ((length l) - 1)

So my question is: is it possible to do define a default return value for this function in case the list is empty?

Maybe this is a silly question and must have skipped something on the documentation or on my internet searches, but it's been only a couple days that I'm learning Haskell and it's a completely different world to me (I only have experience with languages such as Python, Javascript, Java, C, Go...).

Thanks in advance!

EDIT:

First of all: thanks for the answers! It helped me in many ways - not only by solving my problem but also making me understand a few concepts.

You folks gave me a small list of terms and concepts to google and I'm doing it since yesterday. So once again thanks!

Now about the problem. Reading the comments and reading more about lists I came up with this solution:

myLast :: [a] -> Maybe a
myLast xs = case xs of
    [] -> Nothing
    [x] -> Just x
    (_:xs) -> myLast xs

After a few hours reading the comments on this post, and searching about lists itself and patterns, things started to make sense. I'm glad.

Small progress is still progress, right?

like image 756
Márcio Scotuzzi Jr. Avatar asked Feb 07 '26 13:02

Márcio Scotuzzi Jr.


1 Answers

can I declare the list with two possible types?

Yes, but that is not something myLast should be concerned about: you just make a function myLast :: [a] -> Maybe a. If a ~ Either String Int, that's fine. myLast does not need to know the type of the elements. With myLast, it can work with any type.

We return a Nothing in case the list is empty, and a Just x with x the last element if there is such element.

Using length and indexing are often not good ideas: that would mean that you enumerate twice over the same list, which can blow up memory, for example if the list is generated by a function. We can use recursion here. So something along the lines of:

myLast :: [a] -> Maybe a
myLast [] = …
myLast (x : xs) = go xs x
  where
    go [] x = …
    go (x : xs) _ = …

where I leave filling in the parts as an exercise.

Using -1 is likely not a good idea. Imagine a list [0, -1] and [], both would then return -1, but the two scenarios are different.

like image 162
Willem Van Onsem Avatar answered Feb 09 '26 11:02

Willem Van Onsem



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!