实现
filterA2 :: [Char] -> [Char] -> ([Char], [Char])
函数,从两个列表中删除字符'a'
和'A'
,并将结果作为一对返回。例如:
filterA2 "Always" "runAway" == ("lwys", "runwy")
filterA2 "Cherry" "Tree" == ("Cherry", "Tree")
到目前为止,我已经试过了:
filterA2 [] [] = ([], [])
filterA2 ['a'] ['a'] = ([], [])
filterA2 ['A'] ['A'] = ([], [])
filterA2 ['a'] [xs] = ([], [xs])
filterA2 [xs] ['a'] = ([xs], [])
filterA2 ['A'] [xs] = ([], [xs])
filterA2 [xs] ['A'] = ([xs], [])
filterA2 (x:xs) (y:ys) = filterA2 (xs) (ys)
无论我输入什么,它总是返回("", "")
。我可能用了太多的基本情况。
你的方法的问题是:你的模式只有在每个列表中只有一个字符时才有效…
filterA2 :: [Char] -> [Char] -> ([Char], [Char])
filterA2 l1 l2 = (remove l1, remove l2)
where
remove :: [Char] -> [Char]
remove [] = []
remove (x:xs)
|x == 'A' || x == 'a' = remove xs
| otherwise = x : remove xs
import Data.Char (toLower)
filterA2 :: [Char] -> [Char] -> ([Char], [Char])
filterA2 [] [] = ([], [])
filterA2 (x:xs) []
| toLower x == 'a' = (xs', [])
| otherwise = (x:xs', []) where
(xs', _) = filterA2 xs []
filterA2 [] (y:ys)
| toLower y == 'a' = ([], ys')
| otherwise = ([], y:ys') where
(_, ys') = filterA2 [] ys
filterA2 (x:xs) (y:ys)
| toLower x == 'a' && toLower y == 'a' = (xs', ys')
| toLower x == 'a' = (xs', y:ys')
| toLower y == 'a' = (x:xs', ys)
| otherwise = (x:xs', y:ys') where
(xs', ys') = filterA2 xs ys
如果您需要使用显式递归和模式匹配来完成它,上面是使用这些方法的一种方法。当然,使用内置函数会使代码更容易实现和阅读,但您这样做可能是出于教育目的。
您可以看到有4种基本模式,并且每个模式都有特定的案例,作为基于模式的守卫实现。关键思想是每个函数返回一个由2个值组成的元组,这些值是从递归函数调用返回的。
filterA2 (x:xs) (y:ys) = (x:xs', y:ys') where
(xs', ys') = filterA2 xs ys
先不考虑保护和其他情况,看看我们是如何创建元组的。因此,抛开haskell的惰性不讲,即使代码想在每个瞬间尽可能多地计算,它也无法计算函数的返回值,除非它有堆栈下面递归调用的返回值。因此,这是如何发挥的,函数向下递归堆栈,直到它到达底部,基本情况模式匹配,因为两个列表都变成空的:
filterA2 [] [] = ([], [])
此时,最小的函数返回它的值,随后它上面的函数也可以计算并返回它的值,以此类推,直到返回最终结果。