Performance Haskell中无限列表的编译器优化?
我有各种类型的“部分置换”函数,Performance Haskell中无限列表的编译器优化?,performance,optimization,haskell,ghc,Performance,Optimization,Haskell,Ghc,我有各种类型的“部分置换”函数,t->可能是t,它们要么通过返回一个Just将我带到数据结构中的一个新位置,要么如果它们还不能到达那里,则返回一个Nothing 我通常必须在重复的特定模式中应用这些部分置换,建立一个包含所有中间值的列表,但每当我回到起始位置或置换失败时,就会截断该列表 scan_partial_perms :: Eq t => [t -> Maybe t] -> t -> [t] scan_partial_perms ps v = map fromJus
t->可能是t
,它们要么通过返回一个Just
将我带到数据结构中的一个新位置,要么如果它们还不能到达那里,则返回一个Nothing
我通常必须在重复的特定模式中应用这些部分置换,建立一个包含所有中间值的列表,但每当我回到起始位置或置换失败时,就会截断该列表
scan_partial_perms :: Eq t => [t -> Maybe t] -> t -> [t]
scan_partial_perms ps v = map fromJust . takeWhile test $ scanl (>>=) (Just v) ps
where test (Just i) | i /= v = True
test _ = False
iterate_partial_perm = scan_partial_perm . iterate
cycle_partial_perms = scan_partial_perms perms . cycle
我非常确信,scanl
在这种情况下具有理想的严格性和尾部递归特性。关于优化这段代码还有其他提示吗?特别是,除了-O3-fllvm
之外,我应该阅读哪些编译器选项
在最坏的情况下,我可以用如下定义的访问器函数替换scanl
和无限列表
perm l i = l !! i `rem` length l
但是,我认为这不能通过正确的优化来提高性能。我认为您在
扫描部分\u perms
中有一个bug
scan_partial_perms ps v = map fromJust . takeWhile test $ scanl (>>=) (Just v) ps
scanl f s list
总是以s
开头,因此takeWhile测试(scanl…
是[]
。如果这是故意的,那就相当混乱了。假设你想要的是
scan_partial_perms ps v = (v:) . map fromJust . takeWhile test . tail $ scanl (>>=) (Just v) ps
你无能为力。您可以{-#specialize#-}
它,这样Eq
字典就不适用于专门的类型。如果编译器自己不这样做(如果它能看到使用站点的话,它可能会这样做),这将对您有所帮助。使用ghc>=7,您可以将其设置为{-#inlineable#-}
,这样它就可以被专门化,甚至可以在每个使用站点进行内联
我不知道在llvm的道路上会发生什么,但在核心级别,map
、fromJust
和takeWhile
尚未内联,因此如果您非常绝望,如果它们以后在llvm后端中没有内联,您可以通过手动内联来获得十分之几的百分比:
scan_partial_perms ps v = v : go v ps
where
go w (q:qs) = case q w of
Just z
| z /= v -> z : go z qs
_ -> []
go _ _ = []
但这些都是非常廉价的功能,因此收益——如果有的话——将很小
所以你已经拥有了相当好的东西,如果不够好,你需要一种不同的攻击方式
有列表索引的那个
perm l i = l !! (i `rem` length l)
-- parentheses necessary, I don't think (l !! i) `rem` length l was what you want
看起来不太好<代码>长度很贵,
(!!)
也很贵,因此通常应避免使用这两种方法。-O3
与-O2
的意思相同。谢谢!另外,我是否应该将此发布到codereview.SE?我认为这非常适合这样做,因为问题相当具体。哦,是的,我编写的版本可能会失败。我会查一下专业和内联的,谢谢!