从输入Haskell

问题描述

我要创建函数remove :: String -> Char -> String 删除第二个参数中字符的所有实例 从第一个参数中的字符串开始。例如:

remove "ab cd ef" ' ' == "abcdef"

remove "ab cd cf" 'c' == "ab d f"

到目前为止,我有

remove (x:xs) y 
     | x == y     = xs
     | otherwise  = x : remove xs y

这只会删除一个元素,例如如果我写remove "ab cd ef" ' ' 它会打印出"abcd ef"而不是"abcdef"

我需要使用递归创建一个函数,而使用列表推导构建另一个函数

解决方法

正如chi在评论中指出的那样,您需要在两个分支中都使用递归,否则最终只会删除第一个实例。

为完整起见,这里是正确的代码:

remove [] _ = []
remove (x:xs) y
     | x == y     = remove xs y
     | otherwise  = x : remove xs y

如果不包括[]情况,则将出现关于模式匹配的错误-这是因为,当您匹配模式(x:xs)时,您假设数组的长度为> = 1为要定义的x。如果您想到data List a = Cons a (List a) | Empty之类的列表,那么采用列表的任何函数都必须在ConsEmpty构造函数上进行模式匹配。显然,如果您有一个空字符串,则没有什么要删除的,因此对于所有[][]都映射到y

如果您还想要列表理解,请确认列表理解是mapfilter的组合。我们不想更改map允许的字符,只是过滤掉与y匹配的字符。

语法[f x | x <- xs,predicate x]的意思是“从x中取xspredicate x的{​​{1}}中取每个True,并返回表达式列表{{1} }。f xf x部分,map是过滤器部分。

因此我们可以写:

predicate x

请注意,我们不对列表值构造函数进行模式匹配,因此不需要两种情况。 remove xs y = [x | x <- xs,x /= y] 部分只是意味着如果输入列表为空,我们将得到x <- xs。我们还使用[]x代替了id x,我们的谓词是f x

仅供参考,这里不需要x /= y标记,这是元编程语言扩展。