如何计算函数被调用的次数,FP方式

ddk*_*ddk 14 haskell functional-programming

我目前正在与Haskell 一起完成SICP.练习1.15询问函数被调用的次数.这个想法可能是你应该使用替换方法,但我想知道如何在代码中这样做.

在命令式语言中,可以保留全局变量,并在每次调用函数时递增它.但是你会如何在Haskell(或纯粹的功能方式)中实现呢?

bit*_*ket 17

您可以使用Writermonad来完成此操作,前提是所有对相关函数的调用可以组合成一个do块:

import Control.Monad.Writer

myFunc :: Int -> Int -> Writer (Sum Int) Int
myFunc a b = tell (Sum 1) >> return (a + b)

callMyFunc :: ((Int, Int, Int), Sum Int)
callMyFunc = runWriter $ do a <- myFunc 2 3
                            b <- myFunc 8 7
                            c <- myFunc 3 5
                            return (a, b, c)

main = putStrLn $
    "myFunc was called "
        ++ show (getSum $ snd callMyFunc)
        ++ " times and produced "
        ++ show (fst callMyFunc)
Run Code Online (Sandbox Code Playgroud)

哪个输出:

myFunc was called 3 times and produced (5,15,8)
Run Code Online (Sandbox Code Playgroud)


Vla*_*ala 6

对我来说,无论你是使用功能还是非功能方式,都需要有一些计数器.在Haskell中,您可以使用StateMonad来跟踪状态:

import Control.Monad.State

someFunc x = do
    num <- get
    put (num + 1)
    return $ x * x

runSomeFuncs = do
    someFunc 1
    someFunc 2
    someFunc 3

main = do
    let (res, state) = runState runSomeFuncs 0
    putStrLn ("result: " ++ (show res))
    putStrLn ("# of calls: " ++ show state)
Run Code Online (Sandbox Code Playgroud)

在这里,你想跟踪someFunc被调用的次数,所以我们传递一个整数作为状态,并在每次调用函数时使用以下函数递增整数:

num <- get
put (num + 1)
Run Code Online (Sandbox Code Playgroud)

然后将它递增1并put返回.如果您运行此脚本,则应该打印

result: 9
# of calls: 3
Run Code Online (Sandbox Code Playgroud)

  • 或者`修改(+ 1)`而不是`get`ting和`put`ting. (14认同)
  • 在这里使用`State`也允许依赖于计数器,并创建不必要的数据依赖(例如,这会限制并行性).您可以使用`Writer`代替`Sum Int`作为`Monoid`,然后`tell(Sum 1)`来增加计数器.这很好地利用了添加的关联性,并且在多次调用相同的Writer计算时甚至允许CSE. (7认同)