haskell - 在 Haskell 中编写有状态函数

标签 haskell state

允许组合有状态函数的最简单的 Haskell 库是什么?

我们可以使用 State monad 来计算股票的指数加权移动平均线,如下所示:

import Control.Monad.State.Lazy
import Data.Functor.Identity

type StockPrice = Double
type EWMAState = Double
type EWMAResult = Double

computeEWMA :: Double -> StockPrice -> State EWMAState EWMAResult
computeEWMA α price = do oldEWMA <- get
                         let newEWMA = α * oldEWMA + (1.0 - α) * price
                         put newEWMA
                         return newEWMA

但是,编写调用其他有状态函数的函数很复杂。 例如,要查找股票短期平均值与其长期平均值交叉的所有数据点,我们可以这样写:

computeShortTermEWMA = computeEWMA 0.2
computeLongTermEWMA  = computeEWMA 0.8

type CrossingState = Bool
type GoldenCrossState = (CrossingState, EWMAState, EWMAState)
checkIfGoldenCross :: StockPrice -> State GoldenCrossState String
checkIfGoldenCross price = do (oldCrossingState, oldShortState, oldLongState) <- get
                              let (shortEWMA, newShortState) = runState (computeShortTermEWMA price) oldShortState
                              let (longEWMA, newLongState) = runState (computeLongTermEWMA price) oldLongState
                              let newCrossingState = (shortEWMA < longEWMA)
                              put (newCrossingState, newShortState, newLongState)
                              return (if newCrossingState == oldCrossingState then
                                    "no cross"
                                else
                                    "golden cross!")

由于 checkIfGoldenCross 调用computeShortTermEWMA 和computeLongTermEWMA,我们必须手动包装/解开它们的状态。

有没有更优雅的方式?

最佳答案

如果我正确理解您的代码,则您不会在对 computeShortTermEWMAcomputeLongTermEWMA 的调用之间共享状态。它们只是两个完全独立的函数,恰好在内部使用状态。在这种情况下,优雅的做法是将 runState 封装在 computeShortTermEWMAcomputeLongTermEWMA 的定义中,因为它们是独立的包含的实体:

computeShortTermEWMA start price = runState (computeEWMA 0.2 price) start

这一切只是让调用站点变得更整洁;我刚刚将 runState 移至定义中。这标志着该状态是计算 EWMA 的本地实现细节,这才是它的真正含义。 GoldenCrossStateEWMAState 是不同的类型,这一点强调了这一点。

换句话说,您并没有真正编写有状态函数;而是在编写有状态函数。相反,您正在编写恰好在内部使用状态的函数。您可以隐藏该详细信息。

更一般地说,我根本不明白你使用状态来做什么。我想您会用它来迭代股票价格,维护 EWMA。但是,我认为这不一定是最好的方法。相反,我会考虑使用扫描之类的方法在股票价格列表上编写 EWMA 函数。这应该会使您的其他分析函数更容易实现,因为它们也只是列表函数。 (将来,如果您需要处理 IO,您可以随时切换到 Pipes 之类的东西,它提供的界面非常类似于列表。)

关于haskell - 在 Haskell 中编写有状态函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24833714/

相关文章:

haskell - 为什么 Haskell(有时)被称为 "Best Imperative Language"?

algorithm - 使用 Haskell 对排序输入进行分而治之

haskell - 如何在 haskell+cabal 中配置构建依赖项?

javascript - React-Redux : Infinite loop when concat to an array in state?

ios - MKPlacemark() 创建保留周期

javascript - 类型错误 : this is undefined on setstate reactjs

c# - 开关大小写与事件 : On game state update (UNITY, C#)

haskell - Haskell 中的 Pointfree 函数 - 将参数转换为列表

haskell - Parsec String()(String,String)是什么意思?

javascript - Redux:如何追踪数据是否被本地修改?