经过几个小时的调试,我意识到一个非常简单的玩具示例由于缺少!表达式而效率不高return $ 1 + x(感谢 duplode!...但是 ghc 怎么不优化它??)。我也意识到了这一点,因为我将它与更快的 Python 代码进行比较,但我不会总是编写 Python 代码来对我的代码进行基准测试......
所以这是我的问题:有没有办法自动检测这些“懒惰的内存泄漏”,这会无缘无故地减慢程序的速度?我在优化 Haskell 代码方面仍然很糟糕,而且!很可能会忘记 a ,即使您有经验,我猜也是如此。
我知道:
+RTS -s,但我不知道如何解释它:看到79MB的内存为一个简单的程序似乎是巨大的,以我为例子,但也许它不是因为它是什么把我目前的计划......而更大的计划,这是不可能,只是检测我猜是这样的“惰性泄漏”,因为我不知道我的程序应该占用多少内存。cabal v2-run --enable-profiling mysatsolvers -- +RTS -p命令,但似乎使探查杀死由GHC做了一些优化技术,因此它很难使用这些值,真正的标杆。而且,我仍然不清楚如何从该输出中找到泄漏。例如,您能否向我解释如何在这样的玩具程序中找到“懒惰的泄漏”?
{-# LANGUAGE DerivingVia, FlexibleInstances, ScopedTypeVariables #-}
module Main where
--- It depends on the transformers, containers, and base packages.
--- Optimisation seems to be important or the NoLog case will be way to long.
--- $ ghc -O Main.hs
import …Run Code Online (Sandbox Code Playgroud) 当一个操作符被提升为一个定义的高阶函数之一时,Scala允许非常简洁的语法,例如(请忽略它可以简化为.product())的事实:
List(1,2,3).fold(1)(_ * _)
Run Code Online (Sandbox Code Playgroud)
到上面我可以通过 _ \* _
但是在定义了我自己的玩具函数zipWith()之后,我需要在传递函数时非常明确:
implicit class EnrichedList[A](val self: List[A]) extends AnyVal {
def zipWith[B, C](that: List[B])
(implicit zipper: A => B => C): List[C] = {
def zipWithHelper(zipper: A => B => C)
(as: List[A])
(bs: List[B]): List[C] = {
(as, bs) match {
case (_, Nil) => Nil
case (Nil, _) => Nil
case (a :: restOfA, b :: restOfB) =>
zipper(a)(b) :: zipWithHelper(zipper)(restOfA)(restOfB)
}
}
zipWithHelper(zipper)(self)(that)
}
}
Run Code Online (Sandbox Code Playgroud)
这个:List(1, 3, …