簡體   English   中英

為什么Haskell不能優化這個? (在Maybe monad中沒有任何東西被不必要地傳播。)

[英]Why isn't Haskell able to optimize this? (Nothing gets propagated needlessly in the Maybe monad.)

讓我們開始吧

boom :: Int -> Maybe a -> Maybe a
boom 0 x = x
boom n x = boom (n-1) (x >>= (\y -> Just y))

這是一個簡單的函數,只是反復將(或>>= )一個Maybe值推入一個簡單的\\y -> Just y函數。

現在,該計划

main = do
    let z = boom 10 (Nothing :: Maybe Int)
    putStrLn $ show z

一瞬間跑得很快。 但是,該計划

main = do
    let z = boom 10000000 (Nothing :: Maybe Int)
    putStrLn $ show z

即使我使用ghc -O (GHC 7.8.3)進行編譯,也需要幾秒鍾才能完成。

這意味着Haskell無法優化此功能。 即使沒有必要,也Nothing被反復推入函數中。

我的問題是, 為什么 為什么不能推斷出Nothing都不會總是因為反復推遲而Nothing 換句話說, 為什么是不是能夠在第一立即短路 Nothing

你的函數是一個很好的例子,它很慢, 因為它是尾遞歸的 在嚴格的語言中,尾遞歸函數通常是首選,因為它們通常會帶來更好的性能(在時間和空間上)。 在懶惰的尾部遞歸並不是那么有益。 實際上,函數的非尾遞歸變體是:

boom :: Int -> Maybe a -> Maybe a
boom 0 x = x
boom n x = x >>= (\y -> boom (n-1) (Just y))

x是一個Just something時,上面仍會循環n次。 但是,它會在常量空間中執行此操作,而不像在第二個參數中構建大型thunk的原始代碼。 更好的是,當xNothing ,上面的代碼將立即返回。

我確實意識到這並沒有真正回答你關於“為什么”GHC無法對此進行優化的問題。 但希望,它可以表明這些優化非常微妙,並且通常涉及歸納推理。 期望編譯器優化它可能要求有點過多。

你需要使用-fforce-recomp強制重新編譯

ghc編譯得到1.44s

ghc -O編譯得到1.44s

ghc -O -fforce-recomp並得到0.00s到0.04s

注意

它仍然無法使用boom maxBound (Nothing :: Maybe Int)

你會等很長時間。

因為動boom擴大了n-1

所以boom 100 x = boom (100-1) ... = boom (100-1-1) ...等等......

你可以嘗試交換繁榮的論點(但我不確定這會改變什么)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM