patternMinor
99 Haskell Problems - Problem 2
Viewed 0 times
problemproblemshaskell
Problem
Background
This is my first experience with functional programming and totally self-study. I just have 2-3 days' worth experience in Haskell. Now let's continue with actual code.
For Problem 2 of 99 haskell problems I wrote this function
Is this code ok from functional programming perspective? I am open to criticism from any perspective.
EDIT 1
Code after @Pedro Rodrigues suggestions
This is my first experience with functional programming and totally self-study. I just have 2-3 days' worth experience in Haskell. Now let's continue with actual code.
For Problem 2 of 99 haskell problems I wrote this function
module Functions
(
lastButOne
) where
lastButOne :: [a] -> a
lastButOne [a, b] = a
lastButOne (_:xs) = lastButOne xs
lastButOne a = error "Not Supported"Is this code ok from functional programming perspective? I am open to criticism from any perspective.
EDIT 1
Code after @Pedro Rodrigues suggestions
lastButOne :: [a] -> a
lastButOne [a, _] = a
lastButOne (_:xs) = lastButOne xs
lastButOne _ = error "lastButOne requires a list with at least 2 members"Solution
You have the right idea, I just want to make a few remarks:
EDIT: To elaborate more on the safer solution point I mentioned earlier:
In case you haven't heard of
- You could have used
_in the first and the last clause of your function in place of the ignored arguments. It might help readability to know right away that an argument is being ignored.
- You're explicitly throwing an error on invalid input which is fine. A good error message could be more helpful to the caller than just getting a pattern match fail. However it wouldn't have shocked me if you had omitted that last line. An even safer solution is having the function return
Just awhen the input is valid andNothingwhen it's not, but for performance/convenience's sake many partial functions out there don't do that.
EDIT: To elaborate more on the safer solution point I mentioned earlier:
lastButOne has type lastButOne :: [a] -> a. However this type fails to convey that lastButOne is a partial function, and therefore may fail on certain inputs. It's very easy for a caller to overlook that he needs to watch out for invalid inputs. However, had you defined lastButOne as lastButOne :: [a] -> Maybe a instead, then the fact that it might not produce a result for some inputs, is directly encoded in the type of the function, thus making it type safer. Any caller of lastButOne couldn't possibly overlook that he needs to handle failure.In case you haven't heard of
Maybe yet, it's a data structure that is used to elegantly express a computation that may fail. Examples:my_div :: Integer -> Integer -> Maybe Integer
my_div _ 0 = Nothing
my_div a b = Just (div a b)
lastButOne :: [a] -> Maybe a
lastButOne [a, _] = Just a
lastButOne (_:xs) = lastButOne xs
lastButOne _ = Nothing
Context
StackExchange Code Review Q#38840, answer score: 3
Revisions (0)
No revisions yet.