简体   繁体   中英

Combine multiple Haskell functions

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM