>假设我有一个函数concat :: String -> String -> String
。所以
var :: String
var = concat (concat "a" "b") "c") -- "abc"
现在,我有一个函数,我想用它来计算调用 concat 的次数:
func :: (String->String->String) -> Int
因此,func var
应返回 2。
我应该如何获取此值并同时执行连接?
撇开var
的类型错误不谈,你不能。
原因1:你可以编写与var
完全相同的函数,而无需调用concat
。假设concat
的明显定义:
var1 = "a" ++ "b" ++ "c"
或
var2 = "abc"
事实上,当您使用优化进行编译时,编译器会将您的var
变成var2
!
原因 2:如果对concat
的调用次数取决于参数怎么办?应该做什么
func f
where f x y = if x == "" then y else (concat x y)
返回?
正确的方法是将concat :: String -> String -> String
替换为 concatA :: String -> String -> f (String)
,以获得一些适当的Applicative
f
。例如,您可以使用Writer
:
concatW :: String -> String -> Writer Int String
concatW s1 s2 = Writer (s1++s2, Sum 1)
现在
concatW s1 s2 >>= concatW s3 >>= concatW s4
或
(<=) <$> concatW s1 s2 <*> concatW s3 s4
会为你计算事情。
如果您对出于调试目的调用函数的次数感兴趣,则可能需要使用 Debug.Trace
中的trace
。您可能还希望使用探查器并将函数注释为成本中心。如果你疯了,你甚至可以使用unsafePerformIO
。但这些通常不应该出现在已发布的程序中。