gpt4 book ai didi

haskell - 当存在一些递归情况时保持内联的潜力

转载 作者:行者123 更新时间:2023-12-03 16:23:07 25 4
gpt4 key购买 nike

考虑以下数据类型,它只是为了说明:

data D where
D1 :: Int -> D
D2 :: String -> D
DJ :: D -> D -> D

也许还有一个函数,比如 toString:

{-# INLINE toString #-}
toString x = case x of
(D1 x) -> "Int: show x"
(D2 x) -> "String: show x"
(DJ x y) -> "(" ++ toString x ++ "," ++ toString y ++ ")"

(值得注意的是我所做的与打印无关,这只是一个说明性示例)

所以我发现通过像这样定义 toString 可以让我的程序快 15 倍:

{-# INLINE toString #-}
toString x = case x of
(D1 x) -> "Int: show x"
(D2 x) -> "String: show x"
(DJ x y) -> undefined

发生的事情是 toString 现在能够被 GHC 内联。这允许在未来进行大量优化。 DJ 案例是导致问题的原因。所以我尝试了这个:

{-# INLINE toString #-}
toString x = case x of
(D1 x) -> intShow x
(D2 x) -> strShow x
_ -> go x
where
go (D1 x) -> intShow x
go (D2 x) -> strShow x
go (DJ x y) -> "(" ++ go x ++ "," ++ go y ++ ")"
intShow x = "Int: show x"
strShow x = "String: show x"

这实际上意味着它编译速度很快。原因是(我很确定)因为 toString 不再是递归的。 go 是,但 toString 不是。所以编译器会很高兴地内联 toString,允许更多的优化。

但在我看来,上面的代码很丑。

就像我说的,我拥有的功能比这更复杂,而且这种问题在我的代码中出现。我有一个包含很多构造函数的数据类型,有些简单,有些递归。然而,每当我定义一个递归案例时,它甚至会减慢简单的案例。有没有办法保持顶级函数内联而不像我上面那样修改代码?

最佳答案

我没有优雅的解决方案,但也许这样的方法可行。未经测试。

{-# INLINE toString #-}
toString x = go (fix go) -- equivalent to (fix go), but unrolled once
where
{-# INLINE go #-}
go _ (D1 x) -> intShow x
go _ (D2 x) -> strShow x
go k (DJ x y) -> "(" ++ k x ++ "," ++ k y ++ ")"
intShow x = "Int: show x"
strShow x = "String: show x"

关于haskell - 当存在一些递归情况时保持内联的潜力,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42222998/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com