说我有一个函数concat :: String -> String -> String
。所以,
var :: String
var = concat (concat "a" "b") "c") -- "abc"
现在,我有一个函数,我想用它来计算调用concat的次数:
func :: (String->String->String) -> Int
因此,func var
应返回2.
我应该如何获得此值并同时执行concat?
答案 0 :(得分:6)
暂且不说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)
返回?
答案 1 :(得分:6)
执行此操作的正确方法是将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
会为你计算一些事情。
如果您对调用函数的次数感兴趣,可能需要使用trace
中的Debug.Trace
。您可能还想使用分析器并将该功能注释为成本中心。如果你疯了,你甚至可以使用unsafePerformIO
。但这些通常不会出现在已发布的程序中。