我想知道如何在内部解决Haskell模式匹配以及它如何影响性能。假设我们有一个计算成本很高的函数,所以我们在进行实际计算之前预先计算相应输入上的第一个和/或更常用的值和模式匹配:
expensiveComputation :: Int -> Int
expensiveComputation 1 = 101
expensiveComputation 2 = 3333333
expensiveComputation 3 = 42
...
expensiveComputation n = the actual function
如果我们想要的话,我们可以预先计算很多这些案例,但是我们呢?我假设Haskell实际上找到匹配输入的模式需要时间,所以也许它实际上更快计算第1000个值而不是1000个模式匹配?
答案 0 :(得分:14)
我在表格中做了一个简单的测试:
ghc -O2 -ddump-asm -c
使用_c2aD:
movl $28,%ebx ; N.B. the constant 28 matches my largest value
jmp *(%rbp)
_c2aC:
movl $27,%ebx
jmp *(%rbp)
_c2aB:
movl $26,%ebx
jmp *(%rbp)
....
编译。我观察了关键的ASM:
每个顶级等式似乎都是实现的:
_n2aN:
.quad _c2af-(_n2aN)+0
.quad _c2ag-(_n2aN)+0
.quad _c2ah-(_n2aN)+0
.quad _c2ai-(_n2aN)+0
.quad _c2aj-(_n2aN)+0
.quad _c2ak-(_n2aN)+0
...
什么似乎是参考上述实现的跳转表:
_c2aE:
cmpq $25,%r14 ; N.B. the last defined input is 24
jge _c2ae
_u2aH:
testq %r14,%r14
jl _c2ae
_u2aI:
leaq _n2aN(%rip),%rax
addq (%rax,%r14,8),%rax
jmp *%rax
看起来似乎是一对护卫员随后发送:
first = i + 1
那么我认为1000条目的速度会慢吗?不,如果它们是连续的,我敢打赌GHC将生成一个跳转表,就像我在这里看到的一样。另一个有趣的测试是它们是不是连续的。