怎么样
insertSpecial :: Eq a => a -> a -> [a] -> [a]
insertSpecial x y [] = []
insertSpecial x y (a:as) | a == x = y:a:as
insertSpecial x y (a:as) = a : insertSpecial x y as
这种方法使用一种称为递归的通用方法。这意味着手头的任务被分解为一个或几个基本案例,其结果可以很容易地定义,而一般案例可以通过将工作分解为多个部分来解决。在一般情况下,然后在较小的任务上递归调用该函数。目标是最终以基本情况结束,此时工作已完成。另请参阅Learn you a Haskell中的这一部分。
因为insertSpecial
我们可以定义两个基本情况:
如果列表为空,则它不包含我们要查找的元素,并且我们希望在这种情况下保持列表不变,因此我们只需返回一个空列表。我们完成了。
如果列表不为空并且第一个元素是我们要查找的元素,我们将保留y
在该列表的前面并返回它。我们又完成了。
这给我们留下了列表不为空但第一个元素不是我们要查找的元素的情况。在这种情况下,我们将工作(列表)分成两部分:第一个元素和其余元素。insertSpecial
我们将第一个元素放在通过调用列表的其余部分返回的列表的前面。这就是递归发生的地方:insertSpecial
调用本身。
关于这一点可能有点难以理解的一件事是,最后一种情况如何通过在正确的位置插入一个元素来生成一个与原始列表不同的列表。让我们考虑一个例子。假设我们有清单
['h','e','l','o']
请注意,在 Haskell 中,常规字符串只是字符列表,所以['h','e','l','o'] == "helo"
. 另请注意,这['h','e','l','o']
实际上是'h':'e':'l':'o':[]
. (:
接受一个元素和一个列表并将该元素添加到列表中。它也称为cons )。
'l'
现在让我们在前面插入缺失的内容'o'
:
insertSpecial 'o' 'l' "helo"
由于"helo"
is not empty'h'
被绑定到a
并且"elo"
被绑定到as
(此外,'o'
被绑定到x
并且'l'
被绑定到'y'
)。由于a == 'h' /= 'o' == x
我们是第三种情况,所以
insertSpecial 'o' 'l' ('h':"elo") = 'h' : insertSpecial 'o' 'l' "elo"
现在insertSpecial 'o' 'l' "elo"
我们再次陷入第三种情况("elo"
不是空的和'o' /= 'e'
):
insertSpecial 'o' 'l' ('e':"lo") = 'e' : insertSpecial 'o' 'l' "lo"
这又导致了第三种情况:
insertSpecial 'o' 'l' ('l':"o") = 'l' : insertSpecial 'o' 'l' "o"
现在在最后一个调用中,我们实际上绑定'o'
了a
等于,x
然后我们进入第二种情况,在这种情况下,我们将 () 的值y
添加'l'
到a
( 'o'
) 和as
( []
),所以我们得到:
insertSpecial 'o' 'l' ('o':[]) | 'o' == 'o' = 'l' : 'o' : []
将所有这些替换放在一起,我们得到:
insertSpecial 'o' 'l' "helo" =
'h' : insertSpecial 'o' 'l' "elo" =
'h' : 'e' : insertSpecial 'o' 'l' "lo" =
'h' : 'e' : 'l' : insertSpecial 'o' 'l' "o" =
'h' : 'e' : 'l' : 'l' : 'o' : []
并且如上所述'h' : 'e' : 'l' : 'l' : 'o' : [] == ['h','e','l','l','o'] == "hello"
。耶。