请考虑以下事项:
list = [1,3..]
generate n = [compute y | y <- list , (compute y) < n ]
compute a = ... whatever ...
是否可以在到达列表的最后一个元素之前退出生成器 (例如,如果(计算y> 20)? 我想节省计算能力。我只需要小于n的元素。
我是Haskell的新手。一个简单的答案可能是最好的答案。
答案 0 :(得分:8)
关于Haskell的奇妙之处在于它很懒惰。如果你说
> let x = generate 100000
然后Haskell没有立即计算generate 100000
,它只是创建了一个开始计算它的承诺(我们通常将其称为thunk)。
如果您只想要compute y > 20
之前的元素,那么您可以
> takeWhile (<= 20) (generate 100000)
这与您可以执行类似
的语义相同> let nums = [1..] :: [Integer]
这使得对从1到无穷大的所有Integer值的延迟引用。然后你可以做像
这样的事情> take 10 $ map (* 10) $ drop 12345 $ map (\x -> x ^ 2 + x ^ 3 + x ^ 4) $ filter even nums
[3717428823832552480,3718633373599415160,3719838216073150080,3721043351301172120,3722248779330900000,3723454500209756280,3724660513985167360,3725866820704563480,3727073420415378720,3728280313165051000]
虽然这似乎很多工作,但它只计算返回你请求的10个元素所需的最低限度。在这个例子中take 10
的参数仍然是一个无限列表,我们首先抓住所有的平均值,然后将代数表达式映射到它,然后删除前12345个元素,然后将所有剩余(无限)元素乘以10在Haskell中使用无限结构是非常常见的并且通常是有利的。
作为旁注,您当前对generate
的定义会做额外的工作,您需要的更多内容
generate n = [compute_y | y <- list, let compute_y = compute y, compute_y < n]
这种方式compute y
只计算一次,并且您的过滤器compute_y < n
与理解中|
的左侧共享值。另请注意,当您理解条件时,会将其转换为filter
,而不是takeWhile
:
> -- filter applies the predicate to all elements in the list
> filter (\x -> x `mod` 5 == 0) [5,10,15,21,25]
[5,10,15,20]
> -- takeWhile pulls values until the predicate returns False
> takeWhile (\x -> x `mod` 5 == 0) [5,10,15,21,25]
[5,10,15]