Haskell - 一次扫描多个列表

时间:2016-12-28 10:25:10

标签: haskell

做一些大学作业我发现自己做了类似的事情:

scanl' (\acc (a, b, c) -> expression) 0 $ zip3 as bs cs

使用不同数量的压缩列表,最多7个。这似乎效率很低,因为它构造了一个辅助的元组列表。

要递归地定义scanl2, scanl3等并且避免构建额外的列表并不是很困难,但是所需的样板数量是荒谬的。

有没有办法兼顾两者 - 缺少样板和低内存使用?

1 个答案:

答案 0 :(得分:1)

正如评论中所提到的,看起来像生成“额外列表”的Haskell程序实际上很少生成额外的列表(感谢延迟评估等),因此不太可能引入额外的内存使用量。使用Scan.hs。如果函数的使用方式使列表可以在生成时使用,则不会生成任何实际的列表(中间或最终)。

例如,请考虑以下sum程序,该程序在生成import Data.List (scanl') scanl3 :: (acc -> (a, b, c) -> acc) -> acc -> [a] -> [b] -> [c] -> [acc] scanl3 f z as bs cs = scanl' f z $ zip3 as bs cs main = print $ sum $ scanl3 (\z (a, b, c) -> z + a*b + 2*c) 0 [1..100000000] [10,20..] [100,200..] 时使用大型列表:

-O2

如果您使用ghc -prof -rtsopts=all -O2 Scan.hs 优化来编译它以进行性能分析:

./Scan +RTS -h
hp2ps Scan.hp
evince Scan.ps

然后使用堆分析运行它:

zip3

你会发现它在常量内存中运行大约35k),既没有明确创建中间scanl3列表也没有创建最终scanl3列表。

如果在整个列表需要同时保存在内存中的上下文中使用zip3,则中间列表仍然不应该导致任何增加的内存使用,尽管只有可以肯定的是,它将在特定用例中分析它和替代实现。

关于使用zip3作为中间步骤的时间开销,再次确实需要对替代实现进行基准测试。我使用scanl3 :: (acc -> (a, b, c) -> acc) -> acc -> [a] -> [b] -> [c] -> [acc] scanl3 f z (a:as) (b:bs) (c:cs) = z : scanl3 f (f z (a, b, c)) as bs cs scanl3 _ z _ _ _ = [z] 将上述版本与递归版本进行了比较:

-O2

使用与zip3编译的相同的测试用例,发现运行时几乎相同({-# LANGUAGE BangPatterns #-} scanl3 :: (acc -> (a, b, c) -> acc) -> acc -> [a] -> [b] -> [c] -> [acc] scanl3 f !z (a:as) (b:bs) (c:cs) = z : scanl3 f (f z (a, b, c)) as bs cs scanl3 _ z _ _ _ = [z] 为15.2秒,递归为16.8秒)。

请注意,我没有明确地使我的递归版本严格,但在特定的使用情况下(将其与生成时相加),这没有任何区别。

编辑:实际上,我猜它确实有所作为。使用爆炸模式的严格版本:

aws lambda create-function \
--function-name MicroserviceGetAll \
--role arn:aws:iam::<act-id>:role/service-role/microRole \
--handler org.sample.serverless.aws.couchbase.BucketGetAll \
--zip-file fileb:///Users/arungupta/workspaces/serverless/aws/microservice/microservice-http-endpoint/target/microservice-http-endpoint-1.0-SNAPSHOT.jar \
--description "Microservice HTTP Endpoint - Get All" \
--runtime java8 \
--region us-west-1 \
--timeout 30 \
--memory-size 1024 \
--environment Variables={COUCHBASE_HOST=ec2-35-165-83-82.us-west-2.compute.amazonaws.com} \
--publish

看起来它的运行速度可能会持续0.5-1.0秒(超过16秒)。