Home > Mobile >  Haskell Less Input Testing Boilerplate
Haskell Less Input Testing Boilerplate

Time:11-17

Suppose I would like to write a bunch of functions, say func0 to func9. They take the same input but do different things with them. However, all of them involve the same input check. For example:

func0 :: Int -> [a] -> Either String a
func0 i lst
    | i < 0 || i > length lst = Left "Index Out of Bounds!"
    | otherwise = -- does things

The part that checks the index out of bounds is identical for each function, so I would like to not repeat them for each function. Is there any do wizardry to clean the code up a little bit? Thanks in advance!

CodePudding user response:

This seems pretty straightforward to factor out into a higher-order function:

check :: (Int -> [a] -> Either String a) -> Int -> [a] -> Either String a
check f i as
    | i < 0 || i >= length as = Left "Index Out of Bounds!"
    | otherwise = f i as

func0 = check myFunc0

func1 = check myFunc1

and so on, where myFunc0 etc are the parts of the functions which presumably have different behaviour.

(It's not clear what they do, if they all just give a Right value then you probably want to alter them so they simply return an a and put the wrapping in Right in the otherwise clause of check. But the above allows you to return a Left failure value in other circumstances if you need to.)

(I've also changed i > length as to i >= length as because i = length as will also cause a crash assuming you're going to use i as an index.)

CodePudding user response:

I would put the bounds check in the indexing function. Like this:

(!?) :: [a] -> Int -> Either String a
lst !? i = case drop i lst of
    _ | i < 0 -> bad
    [] -> bad
    a:_ -> Right a
    where bad = Left "Index Out of Bounds!"

Now you can write func0 and friends in terms of it without checking the index first, as in:

func0 :: Num a => Int -> [a] -> Either String a
func0 i lst = do
    a <- lst !? (i-1)
    a' <- lst !? (i 1)
    return (a a')
  • Related