Haskell中如何向Maybe类型的列表前置元素?
Haskell 实现返回 Maybe 列表的 zip 函数问题
问题描述
我定义了如下函数:
zip :: [a] -> [b] -> Maybe [(a,b)] zip (headX:tailX) (headY:tailY) = (headX,headY):zip tailX tailY zip _ _ = Nothing
其中递归调用 zip tailX tailY 返回的是 Maybe [(a,b)] 类型,但我尝试用 : 运算符把 (headX,headY) 前置到这个结果上时,编译器报错了——因为 : 仅适用于普通列表,不能直接和 Maybe 类型组合。请问有没有简便的实现方法?
解决方法
方法1:使用 fmap(或 <$>)
利用 fmap 可将函数应用到 Maybe 容器内部值的特性,把 (headX,headY): 这个函数作用到递归返回的 Maybe 列表上:
zip :: [a] -> [b] -> Maybe [(a,b)] zip (x:xs) (y:ys) = (x,y) : <$> zip xs ys zip [] [] = Just [] -- 修正base case:两个空列表应返回Just空列表 zip _ _ = Nothing
注:<$> 是 fmap 的中缀形式,写法更简洁。
方法2:使用 Do 记法
借助 Maybe 的 Monad 特性,用 do 记法提取递归结果并构造新列表:
zip :: [a] -> [b] -> Maybe [(a,b)] zip (x:xs) (y:ys) = do rest <- zip xs ys return $ (x,y) : rest zip [] [] = Just [] zip _ _ = Nothing
方法3:使用 Case 表达式
显式匹配递归调用的结果,手动处理 Just/Nothing 情况:
zip :: [a] -> [b] -> Maybe [(a,b)] zip (x:xs) (y:ys) = case zip xs ys of Just rest -> Just $ (x,y) : rest Nothing -> Nothing zip [] [] = Just [] zip _ _ = Nothing
关键说明
原代码的 base case 存在逻辑问题:当两个输入列表都为空时,应该返回 Just [] 而不是 Nothing,否则会不符合 zip 函数的常规语义——只有当两个列表长度不一致时才返回 Nothing。
内容的提问来源于stack exchange,提问作者chen
相关产品推荐
相关产品推荐

