sieve [] = []
sieve (a:x) = a : sieve [y| y <- x, y `mod` a > 0]
我想将此代码转换为递归实现或使用更高阶函数(如map和filter)。我无法弄清楚我该怎么做。
我尝试过这种方式,但它似乎无法正常工作
sieve (a:x) = f x : map f xs where f = y `mod` a > 0
答案 0 :(得分:3)
这是你想要的那种吗?列表推导仅用于过滤列表,因此我们可以转换为手动应用过滤器的表单。
sieve [] = []
sieve (x:xs) = x : sieve (filter (\y -> y `mod` x > 0) xs)
答案 1 :(得分:3)
除了克里斯的精细答案,归结为“理解代码正在做什么并且直觉正确的翻译”,你可以做更多的机械翻译。列表推导的行为是specified in the Haskell Report:
翻译:列表推导满足这些身份,可以用作内核的翻译:
[e | True] = [e] [e | q] = [e | q, True] [e | b, Q] = if b then [e | Q] else [] [e | p <- l, Q] = let ok p = [e | Q] ok _ = [] in concatMap ok l [e | let decls, Q] = let decls in [e | Q]
其中
e
范围超出表达式,p
超过模式,l
超过列表值表达式,b
超过布尔表达式,decls
超过声明列表,q
超过限定符,Q
超过限定符序列。ok
是一个新变量。函数concatMap
和布尔值True
在Prelude
中定义。
以下是这些规则将如何应用于您的代码。
[y | y <- x, y `mod` a > 0]
= { fourth equation }
let ok y = [y | y `mod` a > 0]
ok _ = []
in concatMap ok x
= { second equation }
let ok y = [y | y `mod` a > 0, True]
ok _ = []
in concatMap ok x
= { third equation }
let ok y = if y `mod` a > 0 then [y | True] else []
ok _ = []
in concatMap ok x
= { first equation }
let ok y = if y `mod` a > 0 then [y] else []
ok _ = []
in concatMap ok x
在此过程之后,您没有列表推导。然后我们可以开始应用我们所知道的其他变换;例如,ok
的第二个子句似乎是死代码,所以:
= { dead code elimination }
let ok y = if y `mod` a > 0 then [y] else []
in concatMap ok x
= { inlining }
concatMap (\y -> if y `mod` a > 0 then [y] else []) x
你是否可以从这个版本的代码直观地跳到filter
当然是另一个问题!但是没有必要实现这一飞跃:这个concatMap
版本根本没有列表推导,并且行为与原始版本完全相同。