[英]Performance in pattern matching
我正在读“ 了解你一个Haskell” ,特别是有关模式匹配的章节。 这是教程中提供的用于计算列表长度的代码:
length' :: (Num b) => [a] -> b
length' [] = 0
length' (_:xs) = 1 + length' xs
我的问题是,反转递归的顺序(通过放置基本情况下)显示任何显着的性能提升?
length' :: (Num b) => [a] -> b
length' (_:xs) = 1 + length' xs
length' [] = 0
不,这没有提供任何性能提升。 在这两种情况下,编译器必须评估它的WHNF参数,以检查它是否为空列表。
实际上,在编译期间很可能会重写此函数,生成代码与您编写的代码完全不同(假设您使用优化编译)。
查看生成的核心( 未经优化编译):
(letrec {
f1_aLn [Occ=LoopBreaker] :: [Integer] -> Integer
[LclId, Arity=1, Str=DmdType]
f1_aLn =
\ (ds_d1gX :: [Integer]) ->
case ds_d1gX of _ [Occ=Dead] {
[] -> fromInteger @ Integer GHC.Num.$fNumInteger 0;
: ds1_d1h4 xs_at0 ->
+ @ Integer
GHC.Num.$fNumInteger
(fromInteger @ Integer GHC.Num.$fNumInteger 1)
(f1_aLn xs_at0)
}; } in
f1_aLn (enumFromTo @ Integer GHC.Enum.$fEnumInteger 1 100))
(letrec {
f2_aBk [Occ=LoopBreaker] :: [Integer] -> Integer
[LclId, Arity=1, Str=DmdType]
f2_aBk =
\ (ds_d1gP :: [Integer]) ->
case ds_d1gP of _ [Occ=Dead] {
[] -> fromInteger @ Integer GHC.Num.$fNumInteger 0;
: ds1_d1gW xs_aBh ->
+ @ Integer
GHC.Num.$fNumInteger
(fromInteger @ Integer GHC.Num.$fNumInteger 1)
(f2_aBk xs_aBh)
}; } in
f2_aBk (enumFromTo @ Integer GHC.Enum.$fEnumInteger 1 100))
我们可以看到编译器生成等效语句。 只是fyi,这是代码:
main = do
print $ f1 [1..100]
print $ f2 [1..100]
f1 [] = 0
f1 (_:xs) = 1 + f1 xs
f2 (_:xs) = 1 + f2 xs
f2 [] = 0
用ghc -ddump-simpl file.hs
只有两个案例,订单并不重要。 在三种情况下,订单不会影响性能,但可能会简化代码。 例如,假设您有一个函数对空列表或单例列表执行大致相同的操作,但是对具有2个或更多项的列表进行递归。 您可以将模式编写得最简单,最复杂:
foo [] = []
foo [x] = [x]
foo (x:y:rest) = x+y : foo (y:rest)
或者,您可以通过先处理更复杂的情况将其减少为两种情况:
foo (x:y:rest) = x+y : foo (y:rest)
foo short = short
因为两个短案件的foo = id
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.