Haskell中如何复用多个同参数函数的相同输入校验逻辑
解决方案
完全可以简化,你可以通过高阶函数抽离公共校验逻辑的方式消除重复代码,也可以结合Either的Monad特性用do notation实现。
方案1:抽离公共校验高阶函数(最简洁)
把索引越界校验逻辑封装成通用的高阶包装函数,后续所有业务函数直接套用该包装器即可:
-- 公共校验包装函数,入参为实际执行业务逻辑的函数 withIndexCheck :: (Int -> [a] -> Either String a) -> Int -> [a] -> Either String a withIndexCheck f i lst -- 注:原示例的判断条件存在边界问题,索引最大有效值为length lst - 1,故用>=替换> | i < 0 || i >= length lst = Left "Index Out of Bounds!" | otherwise = f i lst
后续定义func0到func9时无需再重复写校验逻辑:
func0 :: Int -> [a] -> Either String a func0 = withIndexCheck $ \i lst -> -- 此处直接编写func0专属业务逻辑即可 Right $ lst !! i func1 :: Int -> [a] -> Either String a func1 = withIndexCheck $ \i lst -> -- 此处编写func1专属业务逻辑 if even i then Right (lst !! i) else Left "Index must be even"
方案2:结合do notation实现
如果你本身的业务逻辑有多个Either分支,也可以把校验逻辑封装为单独的Either动作,在do块中优先执行校验,利用Monad的短路特性自动返回错误:
-- 单独封装校验动作 checkIndex :: Int -> [a] -> Either String () checkIndex i lst | i < 0 || i >= length lst = Left "Index Out of Bounds!" | otherwise = Right () func0 :: Int -> [a] -> Either String a func0 i lst = do checkIndex i lst -- 校验失败时会直接短路返回Left,不会执行后续逻辑 -- 此处编写func0专属业务逻辑 Right $ lst !! i
两种方案都可以完全消除校验代码的重复,你可以根据自己业务逻辑的复杂度选择合适的写法。
内容的提问来源于stack exchange,提问作者w41g87
相关产品推荐
相关产品推荐

