jon*_*tar 14 haskell functional-programming list-comprehension
有没有办法使用的方式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
Run Code Online (Sandbox Code Playgroud)
但这些不是范围:
[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'
Run Code Online (Sandbox Code Playgroud)
所以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"
Run Code Online (Sandbox Code Playgroud)
或者,对上面的小例子进行描述,
[x | i<-[0..10], x<-[i*i], x > 20] --works
Run Code Online (Sandbox Code Playgroud)
这看起来有点愚蠢,而且略显缺乏清晰度,因为它看起来效率不高.尽管如此,如果整个理解let还是where在整个理解中工作都会很好.可以这样做吗?
ham*_*mar 24
你这样写:
[x | i <- [0..10], let x = i*i, x > 20]
Run Code Online (Sandbox Code Playgroud)
请注意,没有in.您可以x在术语和后面的任何约束中引用let.这种形式let对应于一个do注释:
do i <- [0..10]
let x = i*i
guard (x > 20)
return x
Run Code Online (Sandbox Code Playgroud)
这里x是从范围let到结束do-块.
你几乎拥有它; 你可以简单地写[x | i <- [0..10], let x = i*i, x > 20](注意,而不是in).它与do-notation 非常相似(事实上,您可以使用do-notation,而最近的GHC扩展使您可以使用列表推导来处理任意monad).如果您很好奇,可以在Haskell 98报告中找到语法:
aexp -> [ exp | qual_1 , ... , qual_n ] (list comprehension, n >= 1)
qual -> pat <- exp (generator)
| let decls (local declaration)
| exp (guard)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,其中一个有效的限定符是let decls,这正是您想要的.