Reputation: 123
I am wondering if there is an easy way to combine some of these functions together to make it a little more clean. The purpose of the function is to take an int list, and return a list containing all elements that occur after the given occurrence of an int.
listAfterFinalKey:: [Int] -> Int -> [Int]
My code works, I was just wondering if there was a better way of writing it. I would ideally like to have it all be in one function (listAfterFinalKey
), but I don't know how to make it work other than having three separate functions. I am also avoiding any build in libraries, and things such as let, and where. I would appreciate if someone could show me how to combine or condense some of this code (if possible).
listAfterFinalKey:: [Int] -> Int -> [Int]
listAfterFinalKey [] x = []
listAfterFinalKey x y = helperFunction1 x y (checker x y 0)
checker:: [Int] -> Int -> Int -> Int
checker [] tracker count = count
checker (x:xs) tracker count = if tracker == x
then checker xs tracker (count+1)
else checker xs tracker count
helperFunction1:: [Int] -> Int -> Int -> [Int]
helperFunction1 [] tracker count = []
helperFunction1 x tracker count = if (count == 0)
then take 1 x ++ helperFunction1 (drop 1 x) tracker count
else if (count /= 0) && (tracker == (head x))
then helperFunction1 (drop 1 x) tracker (count-1)
else helperFunction1 (drop 1 x) tracker count
Upvotes: 1
Views: 741
Reputation: 233447
If you really want to get a good feel for functional programming, it's fine to not immediately jump into using all sorts of built-in functions. Many of those functions, however, are the embodiment of functional programming, so it's useful to learn to use them, and perhaps learn how to replicate them.
The built-in Haskell modules (and, in fact, all Haskell modules I've ever encountered) are open source, so you can easily go and have a look at how they're implemented.
In order to reproduce the above behaviour, you can implement your own versions of elem
, dropWhile
and tail
:
elem' :: Eq a => a -> [a] -> Bool
elem' _ [] = False
elem' target (x:xs) | target == x = True
elem' target (_:xs) = elem' target xs
dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' _ [] = []
dropWhile' p (x:xs) | p x = dropWhile' p xs
dropWhile' _ xs = xs
tail' :: [a] -> [a]
tail' (_:xs) = xs
These three functions work pretty much like their 'official' counterparts - I've just added a '
as a suffix to all three.
You can now easily implement listAfterFinalKey
using those three building blocks:
listAfterFinalKey :: Eq a => [a] -> a -> [a]
listAfterFinalKey xs target | not (elem' target xs) = xs
listAfterFinalKey xs target = tail' (dropWhile' (/= target) xs)
As far as I can tell, it behaves like the OP version:
*Q48735389> listAfterFinalKey [0..9] 3
[4,5,6,7,8,9]
*Q48735389> listAfterFinalKey [0..9] 11
[0,1,2,3,4,5,6,7,8,9]
*Q48735389> listAfterFinalKey [0..9] (-1)
[0,1,2,3,4,5,6,7,8,9]
*Q48735389> listAfterFinalKey [1,2,3,2,1] 2
[3,2,1]
Not only does it drop all elements before it encounters the target
, it also returns the original list if the target
isn't present at all. This is, AFAICT, also the behaviour of the OP function.
In general, head
(and head'
) is unsafe, because it'll throw an exception when passed an empty list. In this simple function, however, this should never happen because tail'
is only called in the case where we know that there's at least one occurrence of target
in xs
.
Note also that the type of listAfterFinalKey
is more general than the OP version.
Upvotes: 1