如何定义一个带有两个列表和输出1列表的追加函数。
因此plusplus [1,2,3] [4,5,6]
应该返回[1,2,3,4,5,6]
。
到目前为止,我有以下内容:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] [] = []
plusplus [] [x] = [x]
plusplus [x] [] = [x]
plusplus (x:xs) (y:ys) = x: plusplus xs (y:ys)
我想定义自己的++
函数,但是使用递归。当我用两个列表实际执行它时,上面的代码给出了一个错误。
这是我通过命令获得的错误示例:
plusplus [1,2,3] [4,5,6]
[1,2,3*** Exception: baby.hs:(...): Non-exhaustive patterns in function plusplus
答案 0 :(得分:5)
好吧,基本上你遇到的唯一问题是缺少案例:
pluspluse (x:xs) [] = ...
缺失(并会导致错误)
但你可以清理一下:
前两种情况基本相同:无论第二个输入是什么结果 - 所以你可以把它作为一个名字(比如说ys
)并写一下:
plusplus [] ys = ys
(你能看到这包括你的前两个案例吗? - 那些ys
是什么?)
你的第3行将被正确的最后一个案例所覆盖(见下文) - 要看到这一点,请记住[x] == x:[]
我会在几分钟内给你完整的答案 - 但你应该试着弄明白:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ? = ??
尝试使用
找到要替换?
和??
的正确内容
你几乎拥有它 - 答案可能是:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ys = x: plusplus xs ys
你可以看到你永远不必触摸第二个列表 - 但需要重新创建所有第一个列表(链接到第二个列表)
答案 1 :(得分:2)
我们知道plusplus = flip (foldr (:))
。以下是foldr
:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr step = let fold acc [] = acc
fold acc (x:xs) = step x (fold acc xs)
in fold
在专业化方面,我们得到:
foldr :: (a -> b -> b) -> b -> [a] -> b
| | | | | |
| | | | | |
(:) :: (a -> [a] -> [a]) | | |
| | |
foldr (:) :: [a] -> [a] -> [a]
这里是专业功能的定义:
fold :: [a] -> [a] -> [a]
fold acc [] = acc
fold acc (x:xs) = x : fold acc xs
当然,我们需要flip
论点:
plusplus :: [a] -> [a] -> [a]
plusplus [] ys = ys
plusplus (x:xs) ys = x : plusplus xs ys
这就是为什么plusplus
被定义的原因。
答案 2 :(得分:1)
谢谢你们!在卡斯滕的帮助下发现了我的愚蠢错误。
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] [] = []
plusplus (x:xs) [] = x:xs
plusplus [] (x:xs) = x:xs
plusplus (x:xs) (y:ys) = x: plusplus xs (y:ys)
这很有效。 所以对于输入:
plusplus [1,2,3] [4,5,6]
输出是:
[1,2,3,4,5,6]
答案 3 :(得分:1)
对卡斯滕的回答来说,这真是一个很好的回答,但我认为这值得进入并且不适合评论。避免函数定义中非穷举模式错误的关键之一是以更机械,公式化的方式处理写入函数。列表类型的定义如下:
data [a] = [] | a : [a]
因此列表类型有两个数据构造函数[]
和:
。因此,在启动函数时首先要尝试的是编写两个方程式,每个方程式对应一个构造函数。 Carsten的模板(我现在主要是复制它)遵循这种模式:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = _ -- Equation for empty list
plusplus (x:xs) ys = _ -- Equation for list cells
既然我们为这个类型的每个构造函数编写了一个模式,我们现在保证我们的模式是详尽的。所以我们盯着我们得到的东西,现在我们看到了解决方案:
plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ys = x : plusplus xs ys
让我们尝试另一个!签名:
-- | Merge two lists by alternating elements of one with the
-- other. After either list runs out, just continue with the
-- remaining elements of the other.
interleave :: [a] -> [a] -> [a]
interleave xs ys = _
让我们通过根据两个构造函数拆分xs
变量将其扩展为两个方程式,并在右侧填写简单部分:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys -- this one was easy
interleave (x:xs) ys = x : _ -- we know it has to start with `x`
现在我们可以采取两种方式。第一个是我们可以采用第二个等式并将其分为两个ys
的案例:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys
interleave (x:xs) [] = x : _
interleave (x:xs) (y:ys) = x : _
填写这些空白很容易:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys
interleave (x:xs) [] = x : xs
interleave (x:xs) (y:ys) = x : y : interleave xs ys
第二种方法是,不要在构造函数的情况下拆分ys
,而要注意这是有效的:
interleave :: [a] -> [a] -> [a]
interleave [] ys = ys
interleave (x:xs) ys = x : interleave ys xs
因此,基于构造函数系统地进行处理,我们确信所有组合都已涵盖。