0

假设我想写一堆函数,func0比如说func9. 他们接受相同的输入,但用它们做不同的事情。但是,它们都涉及相同的输入检查。例如:

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

检查索引越界的部分对于每个函数都是相同的,所以我不想对每个函数重复它们。有什么do魔法可以稍微清理一下代码吗?提前致谢!

4

2 回答 2

2

将其分解为高阶函数似乎非常简单:

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

等等,其中myFunc0etc 是可能具有不同行为的功能部分。

(不清楚它们的作用,如果它们都只给出一个Right值,那么您可能想要更改它们,以便它们简单地返回 ana并将包装放在Rightotherwise子句中check。但上面允许您在其他情况下返回Left失败值如果你需要。)

(我也更改i > length asi >= length as因为i = length as假设您要i用作索引也会导致崩溃。)

于 2021-11-16T17:53:42.067 回答
1

我会将边界检查放在索引函数中。像这样:

(!?) :: [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!"

现在你可以func0不用先检查索引就可以根据它和朋友一起写,如下所示:

func0 :: Num a => Int -> [a] -> Either String a
func0 i lst = do
    a <- lst !? (i-1)
    a' <- lst !? (i+1)
    return (a+a')
于 2021-11-16T19:47:15.337 回答