plx
plx

Reputation: 427

find last element of a list in haskell

I wrote the following code to find the last element of a list in haskell:

myLast (x:xs) = do
    ret <- if xs == [] then x else (myLast xs)
    return ret

The idea is to traverse the list until we are at an element which has the empty list as its next element. When we find it we set ret to that element. It makes sense for me but when I run the code inside the interactive shell I get the following error:

<interactive>:1:1: error:
    • No instance for (Num (m0 b0)) arising from a use of ‘it’
    • In a stmt of an interactive GHCi command: print it

edit 1

The reason I used do was because I saw that pattern being used somewhere to also traverse a list, so I thought I could do the same here. I'am avoiding libraries for now to get comfortable with the language. I wrote the function avoiding the do keyword and now it works:

myLast(x:xs) = if xs == [] then x else (myLast xs)

There's now just an issue with the empty list case. How to approach this in haskell?

Upvotes: 2

Views: 3090

Answers (2)

Will Ness
Will Ness

Reputation: 71070

You want

myLast (x:xs) =

to be equal to

                if xs == [] then x else (myLast xs)

Great, xs == [], so let's just put it back in:

myLast (x:[]) =                  x 

but what about the else part? Well, let's add another equation for that,

myLast (_:xs) =                          myLast xs

and we're golden.

What if we call it with an empty list [] though? No definition case will match, and we will get some kind of a run-time error. Well, same thing happens with the built-in function last too, so we're no better and no worse than Haskell itself here.

What is that match that I mentioned, you ask? That's how Haskell functions get invoked. Each function definition can have several clauses, starting with the function's name, and containing a pattern for each expected argument.

In a left hand side of an equation,

  • (x:[]) is a pattern, matching any singleton list. It can also be written [x]. x will refer to the list's only element, if used in the right-hand side of the equation.

  • [] is a pattern, matching any empty list.

  • (x:xs) is a pattern, matching any non-empty list. x will refer to the list's head (i.e. first) element, if used in the right-hand side of the equation; and xs will refer to the rest of the elements in a list (which are also, a list -- also known as its tail).

But wait, you ask. Wouldn't both clauses match for a singleton list, the first for the pattern [x] and the second for (_:xs) with xs matched up with an empty list, []?

Why yes, they both would match indeed; (x:[]) and (_:xs) are not mutually exclusive.

But that's OK, because in Haskell, if the first clause has matched, that's it -- that is the clause that gets executed, and no other attempts at any additional pattern matching and clause selection are made.

That would be Prolog, and that's quite another language.

Upvotes: 1

karakfa
karakfa

Reputation: 67467

let's start with the signature of your function

myLast :: [a] -> a

now, for an empty list input, what can be expected as the output? How you can make up an instance of an arbitrary type a?

Alternatively, you can defer the handling of missing last element to the callers of your function.

myLast :: [a] -> Maybe a

Upvotes: 2

Related Questions