Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Haskell中无限列表的编译器优化?_Performance_Optimization_Haskell_Ghc - Fatal编程技术网

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?我认为这非常适合这样做,因为问题相当具体。哦,是的,我编写的版本可能会失败。我会查一下专业和内联的,谢谢!