【发布时间】:2016-05-30 13:20:23
【问题描述】:
Haskell 版本(1.03s):
module Main where
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Control.Monad
import Control.Applicative ((<$>))
import Data.Vector.Unboxed (Vector,(!))
import qualified Data.Vector.Unboxed as V
solve :: Vector Int -> Int
solve ar =
V.foldl' go 0 ar' where
ar' = V.zip ar (V.postscanr' max 0 ar)
go sr (p,m) = sr + m - p
main = do
t <- fmap (read . T.unpack) TIO.getLine -- With Data.Text, the example finishes 15% faster.
T.unlines . map (T.pack . show . solve . V.fromList . map (read . T.unpack) . T.words)
<$> replicateM t (TIO.getLine >> TIO.getLine) >>= TIO.putStr
F#版本(0.17s):
open System
let solve (ar : uint64[]) =
let ar' =
let t = Array.scanBack max ar 0UL |> fun x -> Array.take (x.Length-1) x
Array.zip ar t
let go sr (p,m) = sr + m - p
Array.fold go 0UL ar'
let getIntLine() =
Console.In.ReadLine().Split [|' '|]
|> Array.choose (fun x -> if x <> "" then uint64 x |> Some else None)
let getInt() = getIntLine().[0]
let t = getInt()
for i=1 to int t do
getInt() |> ignore
let ar = getIntLine()
printfn "%i" (solve ar)
以上两个程序是Stock Maximize problem的解决方案,时间是Run Code按钮的第一个测试用例。
由于某种原因,F# 版本的速度大约快了 6 倍,但我很确定,如果我用命令式循环替换慢速库函数,我可以将其速度提高至少 3 倍,更有可能提高 10 倍。
Haskell 版本是否可以进行类似的改进?
我这样做是出于学习目的,总的来说,我发现很难弄清楚如何编写高效的 Haskell 代码。
【问题讨论】:
-
只是为了记录,你在测量什么?整个程序的执行(从命令行)或主体的运行时间(使用 sn-p 中未显示的东西)?
-
我曾想象过,对于纯函数式代码,Haskell 至少会领先于 F#。在当前的
4.0版本中,F# 甚至没有内联折叠、扫描和压缩。我想,对于大致相似的纯功能代码,Haskell 应该超过 F#,因为它的纯度提供了优化。 -
我会分别分析 IO 代码和实际计算。您的输入代码当前从文本转换为字符串(使用 T.unpack),然后使用已知非常慢的“读取”。
-
为什么 Haskell 版本使用
replicateM读取所有内容,然后才开始计算? F# 版本不这样做。你不能移动solve以便在replicateM中调用它(并打印它的结果)吗?现在,您似乎正在处理 F# 中不存在的大型列表/文本字符串。 -
@MarkoGrdinic 仅供参考,大多数人都远离wall of text questions。如果你的问题简短而中肯,你会得到更好的回答。
标签: performance haskell f#