简体   繁体   English

如何递归定义自己的haskell函数以追加两个列表?

[英]How to recursively define my own haskell function for appending two lists?

How would I define an append function that takes two lists and output 1 list. 我如何定义一个接受两个列表并输出1个列表的追加函数。

So plusplus [1,2,3] [4,5,6] should return [1,2,3,4,5,6] . 因此plusplus [1,2,3] [4,5,6]应该返回[1,2,3,4,5,6]

I have the following so far: 到目前为止,我有以下内容:

plusplus :: [Int] -> [Int] -> [Int]
plusplus [] [] = []
plusplus [] [x] = [x]
plusplus [x] [] = [x]
plusplus (x:xs) (y:ys) = x: plusplus xs (y:ys)

I want to define my own ++ function, but with recursion. 我想定义自己的++函数,但是要递归。 The code above gives an error when I actually execute it with two lists. 当我实际上用两个列表执行它时,上面的代码给出了一个错误。

This is an example of an error I get with the command: 这是我使用命令得到的错误的示例:

plusplus [1,2,3] [4,5,6] 
[1,2,3*** Exception: baby.hs:(...): Non-exhaustive patterns in function plusplus

ok basically the only problem you have here is a missing case: 好的,基本上,您遇到的唯一问题是缺少一个案例:

pluspluse (x:xs) [] = ...

is missing (and will cause an error) 丢失(将导致错误)

but you can clean up quite a bit: 但您可以清理很多:

The first two cases are basically the same: whatever the second input is will be the result - so you can just it those a name (say ys ) and write: 前两种情况基本上是相同的:无论第二种输入是什么,结果都可以-因此您可以为它们加上一个名称(例如ys )并编写:

plusplus [] ys = ys

(can you see how this includes your first two cases? - what is ys in those?) (你可以看到,这包括你的前两种情况-什么是ys ?那些)


your 3rd line one will be covered by the correct last case (see below) - to see this remember that [x] == x:[] 您的第三行将被正确的最后一种情况覆盖(请参见下文)-要看到这一点,请记住[x] == x:[]


I'll give you the complete answer in a few minutes - but you should try to figure it out: 我会在几分钟内为您提供完整的答案-但您应该尝试找出答案:

plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ? = ??

try to find the correct things to replace ? 试图找到正确的东西来代替? and ?? ?? with


you almost had it - and the answer can be: 您几乎拥有它-答案可以是:

plusplus :: [Int] -> [Int] -> [Int]
plusplus [] ys = ys
plusplus (x:xs) ys = x: plusplus xs ys

as you can see you never have to touch the second list - but need to recreate all of the first list (to link to the second) 如您所见,您不必触摸第二个列表-但需要重新创建所有第一个列表(以链接到第二个列表)

We know that plusplus = flip (foldr (:)) . 我们知道plusplus = flip (foldr (:)) Here's the definition of 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

On specializing, we get: 通过专业化,我们得到:

foldr     :: (a ->  b  ->  b)  ->  b  -> [a] ->  b
              |     |      |       |      |      |
              |     |      |       |      |      |
      (:) :: (a -> [a] -> [a])     |      |      |
                                   |      |      |
foldr (:) ::                      [a] -> [a] -> [a]

Here's the definition of the specialized function: 这是专用功能的定义:

fold :: [a] -> [a] -> [a]
fold acc []     = acc
fold acc (x:xs) = x : fold acc xs

Ofcourse, we need to flip the arguments: 当然,我们需要flip参数:

plusplus :: [a] -> [a] -> [a]
plusplus []     ys = ys
plusplus (x:xs) ys = x : plusplus xs ys

That's the reason why plusplus is defined the way it is. 这就是为什么的原因plusplus定义它是这样的。

Thanks guys! 多谢你们! With the help of Carsten spotting my silly mistake. 在Carsten的帮助下,我发现了愚蠢的错误。

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)

This works. 这可行。 So for input: 因此,输入:

plusplus [1,2,3] [4,5,6]

Output is: 输出为:

[1,2,3,4,5,6]

This is really a riff on Carsten's answer, but I think it's worth going into and won't fit into a comment. 这确实是对Carsten的回答的即兴演说,但我认为值得探讨,不适合发表评论。 One of the keys to avoiding non-exhaustive pattern errors in function definitions is to approach writing functions in a more mechanical, formulaic manner. 避免在函数定义中出现非穷尽的模式错误的关键之一就是以一种更加机械化,公式化的方式来编写函数。 The definition of the list type is something like this: 列表类型的定义是这样的:

data [a] = [] | a : [a]

So list types have two data constructors, [] and : . 因此,列表类型具有两个数据构造函数[]: So a good first thing to try when starting your function is to write two equations, one for each of the constructors. 因此,在启动函数时尝试做的一件好事是编写两个方程,每个构造函数一个。 Carsten's template (which I'm mostly copying now) is following that pattern: Carsten的模板(我现在主要在复制)遵循以下模式:

plusplus :: [Int] -> [Int] -> [Int]
plusplus []     ys = _                -- Equation for empty list
plusplus (x:xs) ys = _                -- Equation for list cells

Now since we've written one pattern for each of the constructors of the type, we're now guaranteed that our patterns are exhaustive. 现在,由于我们为该类型的每个构造函数编写了一个模式,因此现在可以确保我们的模式是详尽无遗的。 So we stare at what we got a bit, and now we see the solution: 因此,我们凝视着所得到的东西,现在我们看到了解决方案:

plusplus :: [Int] -> [Int] -> [Int]
plusplus []     ys = ys
plusplus (x:xs) ys = x : plusplus xs ys

Let's try another one! 让我们再尝试一个! Signature: 签名:

-- | 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 = _

Let's expand this to two equations by splitting the xs variable according to the two constructors, and fill in the easy parts on the right hand side: 让我们通过根据两个构造函数分割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`

Now we can go two ways. 现在我们可以采取两种方式。 The first one is we could take the second equation and split it into two cases for ys : 第一个是我们可以将第二个方程式分解为ys两种情况:

interleave :: [a] -> [a] -> [a]
interleave []     ys     = ys
interleave (x:xs) []     = x : _
interleave (x:xs) (y:ys) = x : _

And filling in those blanks is easy: 填补这些空白很容易:

interleave :: [a] -> [a] -> [a]
interleave []     ys     = ys
interleave (x:xs) []     = x : xs
interleave (x:xs) (y:ys) = x : y : interleave xs ys

The second way is, instead of splitting ys on the constructors' cases, to notice that this works: 第二种方法是,而不是在构造函数的情况下拆分ys ,请注意这可行:

interleave :: [a] -> [a] -> [a]
interleave []     ys = ys
interleave (x:xs) ys = x : interleave ys xs

So by going about it systematically based on the constructors we know for sure that all combinations are covered. 因此,通过基于构造函数系统地进行研究,我们可以确定所有组合均已覆盖。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM