使用 map、concat 替换 3 参数列表理解

发布于 2024-12-10 20:50:29 字数 355 浏览 3 评论 0原文

我对列表理解有一些了解。我理解该表达式:

[x * x | x <- [1..10]]
should output [1,4,9,16,25,36,49,64,81,100]

并且该表达式的效果与以下相同:

map power [1..10]
power x = x * x

现在,我必须找出以下函数的另一种方法(就像上面一样):

[(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]

我无法自己弄清楚没有错误, 请帮我

I have some understanding of list comprehension. I understand that the expression:

[x * x | x <- [1..10]]
should output [1,4,9,16,25,36,49,64,81,100]

and that the effect of that expression is the same as:

map power [1..10]
power x = x * x

Now, I have to find out the other method (just like the above) for the following function:

[(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]

I can't figure it out by myself without errors, please help me

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

痴意少年 2024-12-17 20:50:30
[(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]

相同

concatMap
    (\x -> [(x,y+z) | y <- [1..x], z <- [1..y]])
    [1..10]

与您可以类似地从列表理解中提取 yz 变量 。 (但是您必须按照从左到右的顺序执行此操作:因此 y 接下来,z 最后。)

concatMap 是 Prelude 中定义的函数:

concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = concat . map f
[(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]

is the same as

concatMap
    (\x -> [(x,y+z) | y <- [1..x], z <- [1..y]])
    [1..10]

You can extract the y and z variables out of the list comprehension similarly. (But you must do it in order from left to right: so y next and z last.)

concatMap is a function defined in the Prelude:

concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = concat . map f
心奴独伤 2024-12-17 20:50:30

您可以将其转换为 do 表示法:

foo = do x <- [1..10]
         y <- [1..x]
         z <- [1..y]
         return (x, y+z)

这有效,因为 list 是一个 monad。 do 符号本身只是一元计算的语法糖。遵循脱糖规则(此处在“do 块脱糖”下描述),您最终会得到:

[1..10] >>= (\x -> [1..x] >>= (\y -> [1..y] >>= (\z -> [(x,y+z)])))

运算符 >>=Control.Monad 中定义,相当于带有翻转列表参数的 concatMap。对于列表,return t 只是[t]

You can transform this into do-notation:

foo = do x <- [1..10]
         y <- [1..x]
         z <- [1..y]
         return (x, y+z)

This works because list is a monad. The do-notation itself is just syntactic sugar for a monadic calculation. Following the desugaring rules (described here under "Desugaring of do blocks") you end up with:

[1..10] >>= (\x -> [1..x] >>= (\y -> [1..y] >>= (\z -> [(x,y+z)])))

The operator >>= is defined in Control.Monad, and is equivalent to a concatMap with flipped arguments for lists. return t is just [t] in case of lists.

时间你老了 2024-12-17 20:50:29

Haskell 报告 告诉我们如何翻译列表推导式:

<前><代码>[ e |真 ] = [e]
[ 电子 | q ] = [ e | q,真]
[ 电子 | b, Q ] = 如果 b 则 [ e |问]否则[]
[ e | p <- l, Q ] = 让 ok p = [ e |问]
好的_ = []
在 concatMap 中 ok l
[ e |让 decls, Q ] = 让 decls in [ e |问]

由于您的列表理解仅使用无可辩驳的模式(即,永远不会失败的模式),因此上面的第四个子句有所简化:

[ e | p <- l, Q ]    = concatMap (\p -> [ e | Q ]) l

为了简洁,我将使用此版本,但真正的推导应该使用报告中的定义。 (作业:尝试真正的翻译,并检查最后是否得到“相同的东西”。)让我们尝试一下,好吗?

  [(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]
= concatMap (\x -> [(x,y+z) | y <- [1..x], z <- [1..y]] [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y]]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y], True]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z) | True]) [1..y]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z)]) [1..y]) [1..x]) [1..10]

我们终于得到了一个没有列表推导式的版本。

如果您对 monad 感到满意,那么您还可以通过观察 concatMap 是列表 (>>=) 的翻转版本来深入了解此表达式的行为代码>函数;此外,[e]就像列表的return e。因此,用 monad 运算符重写:

= [1..10] >>= \x ->
  [1..x]  >>= \y ->
  [1..y]  >>= \z ->
  return (x,y+z)

The Haskell Report tells us how to translate list comprehensions:

[ 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 ]

Since your list comprehension only uses irrefutable patterns (that is, patterns that never fail), the fourth clause above simplifies somewhat:

[ e | p <- l, Q ]    = concatMap (\p -> [ e | Q ]) l

I'll use this version for concision, but a true derivation should use the definition from the Report. (Homework: try the real translation, and check that you get the "same thing" in the end.) Let's try it, shall we?

  [(x,y+z) | x <- [1..10], y <- [1..x], z <- [1..y]]
= concatMap (\x -> [(x,y+z) | y <- [1..x], z <- [1..y]] [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y]]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> [(x,y+z) | z <- [1..y], True]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z) | True]) [1..y]) [1..x]) [1..10]
= concatMap (\x -> concatMap (\y -> concatMap (\z -> [(x,y+z)]) [1..y]) [1..x]) [1..10]

And we're finally at a version that has no list comprehensions.

If you're comfortable with monads, then you can also gain insight into the behavior of this expression by observing that concatMap is a flipped version of the list's (>>=) function; moreover, [e] is like the list's return e. So, rewriting with monad operators:

= [1..10] >>= \x ->
  [1..x]  >>= \y ->
  [1..y]  >>= \z ->
  return (x,y+z)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文