为什么这个模式连接而不是返回纯数组?

时间:2014-05-27 06:04:12

标签: haskell

我是哈斯克尔的初学者,现在我发现了一个我不太了解的行为。 在我正在阅读的一本书中有一个练习来编写一个函数,该函数删除了给定char的第一个匹配并让其余的数组不加修改。 经过几次尝试,我想出了有效的代码,但我不知道为什么。代码如下:

removeFirst r [s] 
| s == r = []
| otherwise = [s]
removeFirst r (x:xs)
| r /= x = x : removeFirst r xs
| otherwise = xs

可以请任何人向我解释为什么这个电话

removeFirst 'a' "strange"

而不是返回xs,因此" nge"?为什么连接发生以及代码应该如何获得" nge"?

2 个答案:

答案 0 :(得分:8)

我们只考虑递归情况:

removeFirst r (x:xs)
| r /= x = x : removeFirst r xs
| otherwise = xs

通话顺序为:

  1. removeFirst 'a' "strange": 自'a' /= 's'起,评估结果为's' : removeFirst 'a' "trange"
  2. removeFirst 'a' "trange": 自'a' /= 't'起,评估结果为't' : removeFirst 'a' "range"

    但我们之前的通话中已经有's':,所以我们总是得到

    's': ('t' : removeFirst 'a' "range")

  3. removeFirst 'a' "range": 自'a' /= 'r'起,评估结果为'r' : removeFirst 'a' "ange"

    但我们之前的通话中已经有's':'t':,所以我们总是得到

    's' : ('t' : ('r' : removeFirst 'a' "ange")

  4. removeFirst 'a' "ange": 由于'a' /= 's'false,因此评估为xs,在本例中为"nge"

    但我们之前的通话中已经有's':'t':'r':,所以我们总得's':'t':'r':"nge"

  5. <强>更新

    @Zeta在Pastebin提供了评估条款的精彩摘要,我在这里无耻地包括:

    removeFirst 'a' "strange"
    = 's' : removeFirst 'a' "trange"
    = 's' : 't' : removeFirst 'a' "range"
    = 's' : 't' : 'r' : removeFirst 'a' "ange"
    = 's' : 't' : 'r' : "nge"
    = "strnge"
    

答案 1 :(得分:2)

不是关于你的问题的答案(你已经得到了很好的答复),但是关于你的功能风格的评论:过于命令,不够功能/类型驱动。

当你编写一个处理列表(或任何递归类型)的函数时,总是先从基本情况(空列表,节点......)开始,然后考虑 inductive < / em>(递归) case(s)(这里有一个列表,可以是空列表,但我们不需要关心已经在基地检查过情况)。

考虑到这一点,当我们查看您的代码时,我们首先注意到您的模式匹配并非详尽无遗,因为您忘记了基本情况,空列表情况:

removeFirst _ [] = []
-- removing the first matching element of an empty list is just
-- returning that empty list

和你的2个模式匹配是一样的,第一个是第二个写的颠倒,专门用于一个项目长列表;重写以比较两者:

removeFirst r (x:[])  -- removeFirst r (x:xs)
 | x /= r    = x : [] --  | x /= r    = x : removeFirst r xs
 | otherwise = []     --  | otherwise = xs

最后,你可以写:

removeFirst _ [] = [] -- "_" as we don't care about the character to remove
removeFirst r (x:xs)
 | x == r    = xs
 | otherwise = x : removeFirst r xs

(只是一个品味问题:我更喜欢在开头和递归的情况下将非递归情况分组到最后。)