有没有办法重复绑定?

时间:2016-04-12 03:56:51

标签: haskell monads

我维护了一些代码,遗憾的是,广泛使用引用来跟踪程序中的状态。在一个模块中使用它们特别令人震惊,它通过欧拉方法更新了许多值:

eulerUpdate states timestep = do
  _val1  <- readReference (val1 states)
  _dval1 <- readReference (dval1 states) 
  _val2  <- readReference (val2 states)
  _dval2 <- readReference (dval2 states)
    -- ...
  _valn  <- readReference (valn states)
  _dvaln <- readReference (dvaln states)
  let euler val deriv = val + deriv * timestep
  writeReference (val1 states) euler _val1 _dval1
    -- ...
  writeReference (valn states) euler _valn _dvaln

我对Haskell相对较新,但我的理解是,这是一个可怕的,可怕的,不好的,非常糟糕的事情。我没有重构其周围的所有其他东西,而是希望可能有某种方法至少将它压缩到更少的LOC以便于阅读。是否有任何可以在这里完成的事情&#34; map&#34;将readReference (x states)变成一堆标识符?我更多地看了Kliesli的箭,但是我看不到有什么能帮助我。

1 个答案:

答案 0 :(得分:1)

首先:是否可以重新安排读写操作?如果是这样,您可以使用像

这样简单的东西
let updateOne val dval = do
    _val = readReference (val states)
    _dval = readReference (dval states)
    writeReference (val states) (euler _val _dval)

然后就像

一样使用它
eulerUpdate states timestep = do
    updateOne val1 dval1
    updateOne val2 dval2
    ...

如果没有,并且写不好阅读,那么,您可能希望获得创造性并将读写操作分开,但是在相同的结构中:

data ReadWriteReference where
    ReadWriteReference :: (States -> IO a) -> (States -> a -> IO ()) -> ReadWriteReference
performReadWrite :: States -> ReadWriteReference -> IO ()
performReadWrite states (ReadWriteReference read write) = do
    a <- read states
    write states a
makeRW :: (States -> Reference) -> (States -> Reference) -> ReadWriteReference
makeRW val dval = ReadWriteReference read write where
    read states = do
        _val <- readReference (val states)
        _dval <- readReference (dval states)
        writeReference (val states) (euler _val _dval)
(<+>) :: ReadWriteReference -> ReadWriteReference -> ReadWriteReference
ReadWriteReference read1 write1 <+> ReadWriteReference read2 write2 = ReadWriteReference read write where
    read states = do
        a <- read1 states
        b <- read2 states
        return (a, b)
    write states (a, b) = do
        write1 states a
        write2 states b

现在您可以像这样使用它:

performReadWrite states $ makeRW val1 dval1 <+> makeRW val2 dval2 <+> ... <+> makeRW valn dvaln

您甚至可以将ReadWriteReference作为Monoid的实例并使用标准组合器。