将List理解转换为递归调用

时间:2013-12-05 17:38:30

标签: haskell recursion higher-order-functions

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

2 个答案:

答案 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和布尔值TruePrelude中定义。

以下是这些规则将如何应用于您的代码。

[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版本根本没有列表推导,并且行为与原始版本完全相同。