Haskell:Monad变压器和全球状态



我正在尝试学习Haskell。我正在尝试编写一个包含"全局状态"的程序:Vars.我想更改状态的一个组件(例如var1( 每次调用函数时。更改可以是组件上的简单功能(例如 +4(。此外,它还打印出更改的组件。这是我到目前为止所做的(但我被困住了(。编辑:运行代码后,我想查看最新版本的全局状态。

import Control.Monad.State
import Control.Monad.IO.Class (liftIO)
data Vars = Vars {
var1 :: Int,
var2 :: Float
} deriving (Show)
sample :: StateT Vars IO a
sample = do 
a <- change
liftIO $ print a
-- I want to call change again and apply more change to the state

change  :: StateT Vars IO a
change  = do
dd <- get
-- I don't know what to do next!
main = do 
runStateT sample (Vars 20 3)
evalStateT sample (Vars 20 3)

让我们尝试从更简单的小部分开始逐步解决您的问题。这是编程中的重要技能,FP以很好的方式教你这项技能。此外,使用Statemonad,尤其是 monad-transformer 中的几种效果,可以帮助您推理效果并更好地理解事物。

  1. 您希望在不可变数据类型中更新var1。这只能通过创建新对象来完成。所以让我们写这样的函数:

    plusFour :: Vars -> Vars
    plusFour (Vars v1 v2) = Vars (v1 + 4) v2
    

    Haskell中有一些方法可以编写这个函数,尽管不太容易理解,但我们现在不关心这些事情。

  2. 现在,您想在 monad 中使用这个函数来更新不可变状态State并通过此模拟可变性。仅通过查看其类型签名即可了解此函数:change :: StateT Vars IO a?我们可以说这个函数有几个效果:它可以访问Vars状态,并且可以执行任意IO操作。此外,此函数返回类型为a的值。嗯,最后一个很奇怪。什么是a?此函数应返回什么?在命令式编程中,此函数将具有类型voidUnit。它只是事,它不会返回所有内容。仅更新上下文。所以它的结果类型应该是()。它可以是不同的。例如,我们可能希望在更改后返回新Vars。但这在编程中通常是不好的方法。它使此功能更加复杂。

  3. 在我们了解了类型函数应该具有什么(尝试始终从定义类型开始(之后,我们可以实现它。我们想改变我们的状态。有些函数使用上下文的有状态部分进行操作。基本上,你对这个感兴趣:

    modify :: Monad m => (s -> s) -> StateT s m ()

    modify函数采用更新状态的函数。运行此函数后,您可以观察到状态根据传递的函数进行了修改。现在change可以这样写:

    change :: StateT Vars IO ()
    change = modify plusFour
    

    您可以实现modify(因此change仅使用putget函数,这对初学者来说是很好的练习(。

  4. 现在让我们从其他函数调用change函数。在这种情况下,调用是什么意思?这意味着您执行一元操作change。此操作会更改您的上下文,您不关心它的结果,因为它()。但是,如果您在change之后运行get函数(将整个状态绑定到变量(,则可以观察到新的变化。如果您只想打印更改的组件,例如var1您可以使用gets功能。而且,再说一次,sample应该拥有什么类型?它应该返回什么?如果在调用方,您只对结果状态感兴趣,那么,同样,它应该像这样()

    sample :: StateT Vars IO ()
    sample = do
    change
    v1 <- gets var1
    liftIO $ print v1
    change
    v1' <- gets var1 
    liftIO $ print v1'  -- this should be v1 + 4
    

这应该会让您对正在发生的事情有所了解。Monad变压器需要一些时间来适应它们,尽管它是一个强大的工具(不完美,但非常有用(。

作为旁注,我想补充一点,使用常见的Haskell设计模式可以更好地编写这些函数。但是你现在不需要关心这些,只要试着了解这里发生了什么。

最新更新