使用过滤器进行列表理解的最有效方法

时间:2016-03-11 00:37:03

标签: haskell

我正在学习Haskell并且来自Python,所以列表理解很熟悉。把这个列表理解(请):

[x^2 | x <- [1..10], x^2 < 50]
[1,4,9,16,25,36,49]

表达式x^2是否会在x的每个值上进行两次评估?有没有办法写出这种理解,使表达式x^2只被评估一次?做这样的事情是否有意义:

filter (< 50) [x^2 | x <- [1..10]]
[1,4,9,16,25,36,49]

这是做事的“Haskell方式”吗?它也更有效率吗?

2 个答案:

答案 0 :(得分:7)

您可以在列表推导中使用let

[ z | x <- [1..10], let z = x^2, z < 50]

然后x^2只评估一次。

答案 1 :(得分:4)

我这样做,这与你的第二个例子相似:

filter (<50) (map (^2) [1..10])

我对列表理解有偏见。他们基本上只做三件事(映射,过滤和交叉产品),并且你希望拥有比这三者更大的操作词汇。研究Data.List模块。

关于性能,我们可以使用criterion库轻松地对其进行基准测试而无需太多精力。 (我已经a repo here了 - 您可以使用the Stack tool进行构建。)

import Criterion.Main

main = defaultMain
       [ bgroup "one" [ bench "10"    $ nf one 10
                      , bench "100"   $ nf one 100
                      , bench "1000"  $ nf one 1000
                      , bench "10000" $ nf one 10000
                      ]
       , bgroup "two" [ bench "10"    $ nf two 10
                      , bench "100"   $ nf two 100
                      , bench "1000"  $ nf two 1000
                      , bench "10000" $ nf two 10000
                      ]
       , bgroup "three" [ bench "10"    $ nf three 10
                        , bench "100"   $ nf three 100
                        , bench "1000"  $ nf three 1000
                        , bench "10000" $ nf three 10000
                        ]
       ]

one :: Int -> Int
one n = sum [x^2 | x <- [1..n], x^2 < n*5]

two :: Int -> Int
two n = sum (filter (<(5*n)) [x^2 | x <- [1..n]])

three :: Int -> Int
three n = sum (filter (<(5*n)) (map (^2) [1..n]))

我得到了这些结果,对我来说这表明它并没有产生很大的影响(如果有的话):

% stack install --ghc-options='-O2'
Copied executables to /Users/luis.casillas/.local/bin:
- comprehension

% comprehension
benchmarking one/10
time                 18.40 ns   (18.35 ns .. 18.45 ns)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 18.38 ns   (18.33 ns .. 18.42 ns)
std dev              143.7 ps   (116.9 ps .. 173.6 ps)

benchmarking one/100
time                 89.11 ns   (88.49 ns .. 89.72 ns)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 88.78 ns   (88.42 ns .. 89.44 ns)
std dev              1.582 ns   (1.231 ns .. 2.103 ns)
variance introduced by outliers: 23% (moderately inflated)

benchmarking one/1000
time                 649.2 ns   (640.7 ns .. 658.7 ns)
                     0.998 R²   (0.998 R² .. 0.999 R²)
mean                 647.6 ns   (637.8 ns .. 658.0 ns)
std dev              31.40 ns   (24.70 ns .. 40.84 ns)
variance introduced by outliers: 66% (severely inflated)

benchmarking one/10000
time                 6.197 μs   (6.079 μs .. 6.282 μs)
                     0.997 R²   (0.996 R² .. 0.998 R²)
mean                 6.180 μs   (6.058 μs .. 6.295 μs)
std dev              436.0 ns   (371.1 ns .. 531.8 ns)
variance introduced by outliers: 77% (severely inflated)

benchmarking two/10
time                 20.23 ns   (19.89 ns .. 20.56 ns)
                     0.999 R²   (0.998 R² .. 0.999 R²)
mean                 19.89 ns   (19.71 ns .. 20.11 ns)
std dev              709.8 ps   (582.1 ps .. 939.1 ps)
variance introduced by outliers: 58% (severely inflated)

benchmarking two/100
time                 83.95 ns   (83.14 ns .. 84.90 ns)
                     0.999 R²   (0.999 R² .. 1.000 R²)
mean                 83.34 ns   (82.59 ns .. 83.99 ns)
std dev              2.354 ns   (1.890 ns .. 3.043 ns)
variance introduced by outliers: 44% (moderately inflated)

benchmarking two/1000
time                 645.3 ns   (635.8 ns .. 655.4 ns)
                     0.998 R²   (0.997 R² .. 0.999 R²)
mean                 652.9 ns   (643.1 ns .. 664.5 ns)
std dev              35.54 ns   (29.67 ns .. 46.19 ns)
variance introduced by outliers: 71% (severely inflated)

benchmarking two/10000
time                 6.268 μs   (6.142 μs .. 6.385 μs)
                     0.998 R²   (0.997 R² .. 0.999 R²)
mean                 6.200 μs   (6.099 μs .. 6.367 μs)
std dev              397.6 ns   (261.9 ns .. 637.4 ns)
variance introduced by outliers: 73% (severely inflated)

benchmarking three/10
time                 18.96 ns   (18.66 ns .. 19.32 ns)
                     0.998 R²   (0.998 R² .. 0.999 R²)
mean                 19.17 ns   (18.92 ns .. 19.49 ns)
std dev              990.6 ps   (774.2 ps .. 1.393 ns)
variance introduced by outliers: 75% (severely inflated)

benchmarking three/100
time                 89.01 ns   (88.39 ns .. 89.78 ns)
                     0.998 R²   (0.997 R² .. 0.999 R²)
mean                 92.60 ns   (90.78 ns .. 98.08 ns)
std dev              9.138 ns   (5.755 ns .. 14.22 ns)
variance introduced by outliers: 91% (severely inflated)

benchmarking three/1000
time                 638.9 ns   (627.9 ns .. 648.7 ns)
                     0.996 R²   (0.994 R² .. 0.998 R²)
mean                 643.6 ns   (627.9 ns .. 660.6 ns)
std dev              48.67 ns   (38.78 ns .. 61.57 ns)
variance introduced by outliers: 83% (severely inflated)

benchmarking three/10000
time                 6.060 μs   (5.989 μs .. 6.119 μs)
                     0.998 R²   (0.997 R² .. 0.999 R²)
mean                 6.124 μs   (6.036 μs .. 6.240 μs)
std dev              359.7 ns   (294.9 ns .. 431.9 ns)
variance introduced by outliers: 69% (severely inflated)