AJF*_*mar 3 haskell functional-programming traversal
在haskell wiki的"编程技巧"部分中,我找到了这个例子:
count :: (a -> Bool) -> [a] -> Int
count p = length . filter p
Run Code Online (Sandbox Code Playgroud)
据说这是一个更好的选择
count :: (a -> Bool) -> [a] -> Int
count _ [] = 0
count p (x:xs)
| p x = 1 + count p xs
| otherwise = count p xs
Run Code Online (Sandbox Code Playgroud)
就可读性而言,我完全同意.
但是,这不是一个双遍历,因此实际上比显式递归函数更糟糕吗?GHC中的懒惰是否意味着这相当于优化后的单个遍历?哪种实现更快,为什么?
ram*_*ion 11
那么为了看看优化器实际上做了什么,让我们来看看核心:
% ghc -O2 -ddump-simpl Temp.hs
[1 of 1] Compiling Temp ( Temp.hs, Temp.o )
==================== Tidy Core ====================
Result size of Tidy Core = {terms: 29, types: 26, coercions: 0}
Temp.count
:: forall a_arN.
(a_arN -> GHC.Types.Bool) -> [a_arN] -> GHC.Types.Int
[GblId,
Arity=2,
Caf=NoCafRefs,
Str=DmdType <L,C(U)><S,1*U>,
Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=2, Value=True,
ConLike=True, WorkFree=True, Expandable=True,
Guidance=IF_ARGS [60 0] 191 0}]
Temp.count =
\ (@ a_aMA)
(p_arV :: a_aMA -> GHC.Types.Bool)
(eta_B1 :: [a_aMA]) ->
letrec {
go_aNr [Occ=LoopBreaker]
:: [a_aMA] -> GHC.Prim.Int# -> GHC.Types.Int
[LclId, Arity=1, Str=DmdType <S,1*U>]
go_aNr =
\ (ds_aNs :: [a_aMA]) ->
case ds_aNs of _ [Occ=Dead] {
[] -> GHC.Types.I#;
: y_aNx ys_aNy ->
case p_arV y_aNx of _ [Occ=Dead] {
GHC.Types.False -> go_aNr ys_aNy;
GHC.Types.True ->
let {
g_a10B [Dmd=<L,C(U)>] :: GHC.Prim.Int# -> GHC.Types.Int
[LclId, Str=DmdType]
g_a10B = go_aNr ys_aNy } in
\ (x_a10C :: GHC.Prim.Int#) -> g_a10B (GHC.Prim.+# x_a10C 1)
}
}; } in
go_aNr eta_B1 0
Run Code Online (Sandbox Code Playgroud)
清理一下:
Temp.count :: forall aType. (aType -> Bool) -> [aType] -> Int
Temp.count = \(@ aType) (p :: aType -> Bool) (as :: [aType]) ->
letrec {
go :: [aType] -> GHC.Prim.Int# -> Int
go = \(xs :: [aType]) ->
case xs of _ {
[] -> I#; -- constructor to make a GHC.Prim.Int# into an Int
: y ys ->
case p y of _ {
False -> go ys;
True ->
let {
go' :: GHC.Prim.Int# -> Int
go' = go ys
} in \(x :: GHC.Prim.Int#) -> go' (GHC.Prim.+# x 1)
}
};
} in go as 0
Run Code Online (Sandbox Code Playgroud)
由于我们在unboxed类型上运行GHC.Prim.Int#,所有添加都是严格的,所以我们只有一个循环通过数据.
| 归档时间: |
|
| 查看次数: |
131 次 |
| 最近记录: |