haskell - 让/在列表理解中等效吗?
有没有办法在列表理解中使用 let
、where
或以其他方式定义子表达式,以便它可以在术语和约束中使用?
根据我的实验,以下工作:
[let x = i*i in x | i<-[1..10], i*i > 20] --good
[i*i | i<-[1..10], let x=i*i in x > 20] --good
但这些不属于范围:
[let x = i*i in x | i<-[1..10], x > 20] -- 'x' not in scope error
let x = i*i in [x | i<-[1..10], x > 20] -- 'i' not in scope error
[x | i<-[1..10], x > 20] where x = i*i --parse error on 'where'
所以 let
在一个地方或另一个地方工作,但不能同时工作!
我发现让它工作的唯一方法(即,避免重复的表达式和可能的评估)是添加一个愚蠢的单例列表,就像我在这里使用 x<-[cat i [1..k] 所做的那样
作为列表理解的约束:
> let cat x l = foldl1 (++) $ map show [x*i | i<-l]
maximum [x| i<-[1..9999], k<-[2..div 10 $ length $ show i], x<-[cat i [1..k]], sort x == "123456789"]
"932718654"
或者,继续上面的简单示例,
[x | i<-[0..10], x<-[i*i], x > 20] --works
这看起来有点愚蠢,并且稍微缺乏清晰度,但它看起来效率并不算太低。不过,如果 let
或 where
能够在整个理解过程中发挥作用,那就太好了。这可以做到吗?
Is there a way to use let
,where
or otherwise define sub-expressions in a list comprehension so that it can be used both in the term and constraint?
From my experimenting, the following work:
[let x = i*i in x | i<-[1..10], i*i > 20] --good
[i*i | i<-[1..10], let x=i*i in x > 20] --good
But these do not bc of scope:
[let x = i*i in x | i<-[1..10], x > 20] -- 'x' not in scope error
let x = i*i in [x | i<-[1..10], x > 20] -- 'i' not in scope error
[x | i<-[1..10], x > 20] where x = i*i --parse error on 'where'
So let
works in one place or the other, but not both together!
The only way I've found to make it work (that is, avoid repeated expressions and possibly evaluations) is to add a silly singleton-list as I did here with x<-[cat i [1..k]
as a constraint to the list comprehension:
> let cat x l = foldl1 (++) $ map show [x*i | i<-l]
maximum [x| i<-[1..9999], k<-[2..div 10 $ length $ show i], x<-[cat i [1..k]], sort x == "123456789"]
"932718654"
Or, contunuing the trivial example above,
[x | i<-[0..10], x<-[i*i], x > 20] --works
This seems a little silly, and is slightly lacking in clarity, tho it doesn't seem too inefficient. Still, it would be nice if let
or where
worked across the whole comprehension. Can this be done?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你可以这样写:
注意没有
in
。您可以在该术语以及let
后面的任何约束中引用x
。这种形式的let
对应于do
表示法中的形式:这里
x
的范围是从let
到do
块的末尾。You write it like this:
Notice there is no
in
. You can refer tox
in both the term, and any constraints following thelet
. This form oflet
corresponds to the one indo
-notation:Here
x
is in scope from thelet
to the end of thedo
-block.你几乎已经拥有它了;你可以简单地写
[x | i <- [0..10],设 x = i*i,x > 20]
(注意,
而不是in
)。它与 do 表示法非常相似(事实上,您可以使用 do 表示法,最近的 GHC 扩展使您能够对任意 monad 使用列表推导式)。如果您好奇,可以在 Haskell 98 报告中找到语法:如您所见,有效的限定符之一是
let decls
,这正是您想要的。You almost had it; you can simply write
[x | i <- [0..10], let x = i*i, x > 20]
(note the,
instead ofin
). It's very similar todo
-notation (in fact, you can usedo
-notation instead, and a recent GHC extension enables you to use list comprehensions for arbitrary monads). If you're curious, you can find the syntax in the Haskell 98 report:As you can see, one of the valid qualifiers is
let decls
, which is exactly what you wanted.