使用仿函数来表示全局变量?

Xod*_*rap 2 haskell functor

我正在学习Haskell,并正在实现一个类的算法.它工作正常,但是类的要求是我保持计数乘以或加两个数的总次数.这就是我在其他语言中使用全局变量的原因,我的理解是它对Haskell来说是诅咒.

一种选择是让每个函数返回此数据及其实际结果.但这似乎并不好玩.

这就是我的想法:假设我有一些功能f :: Double -> Double.我可以创建一个数据类型,(Double, IO)然后使用仿函数来定义乘法中的乘法(Double, IO)来进行乘法并向IO写入内容.然后我可以将我的新数据传递到我的函数中.

这有意义吗?有更简单的方法吗?

编辑:更清楚的是,在OO语言中,我将声明一个继承自然Double后覆盖*操作的类.这将允许我不必重写我的函数的类型签名.我想知道在Haskell中是否有某种方法可以做到这一点.

具体来说,如果我定义f :: Double -> Double那么我应该能够做functor :: (Double -> Double) -> (DoubleM -> DoubleM)对吗?然后我可以保持我的功能与现在一样.

mok*_*kus 5

实际上,你的第一个想法(用每个值返回计数)并不是坏的,并且可以由Writer monad(Control.Monad.Writer来自mtl包或Control.Monad.Trans.Writer变换器包)更抽象地表达.从本质上讲,编写器monad允许每个计算都有一个关联的"输出",只要它是一个实例,它就可以是任何东西Monoid- 一个定义的类:

  • 空输出(mempty),即分配给'return'的输出
  • 组合输出的关联函数(`mappend'),用于排序操作

在这种情况下,输出是一个操作计数,'empty'值是零,并且组合操作是加法.例如,如果您要单独跟踪操作:

data Counts = Counts { additions: Int, multiplications: Int }
Run Code Online (Sandbox Code Playgroud)

使该类型成为Monoid(在模块中Data.Monoid)的实例,并将您的操作定义为:

add :: Num a => a -> a -> Writer Counts a
add x y = do
    tell (Counts {additions = 1, multiplications = 0})
    return (x + y)
Run Code Online (Sandbox Code Playgroud)

作者monad与你的Monoid实例一起,负责将所有'tell'传播到顶层.如果你愿意,你甚至可以实现一个Num实例Num a => Writer Counts a(或者,最好是为新类型实现你不创建一个孤立实例),这样你就可以使用普通的数值运算符.