gpt4 book ai didi

Haskell:如何在纯函数中产生副作用

转载 作者:行者123 更新时间:2023-12-01 14:06:21 25 4
gpt4 key购买 nike

我是一个 Haskell 初学者,对于如何在一些纯函数中呈现一些副作用感到很困扰,即非常简单的 size功能...

size :: [Int] -> StateT Int IO ()
size = fmap (\x -> do
num <- get
put (num + 1)
return x) -- some pseudo code like this...

我知道有很多错误... return我的意思是这个 lambda 返回 x本身,这样列表的值就不会被改变......事实上,我想使用 StateT呈现一些副作用。我怎么能这样做?谢谢。

最佳答案

首先,在学习过程的这一点上,您可能不应该担心“副作用”。您还试图混合两个单子(monad),StateIO ,在你似乎也没有掌握的地步。因此,您可能应该更轻松一些。

可以在 IO 中执行有状态操作。 monad 使用 IORefs ,您可以将其视为可变变量。如果我是你,我还不会去那里。然后是State monad,粗略地说,是一种在纯环境中模拟有状态函数的便捷方式。

理论上,你可以想到一个有状态的函数f :: a -> b作为 f :: (a,s) -> (b,s) 类型的纯函数, 其中 s表示您可以访问和更改的某些状态。上面的内容不太适合 monad 框架,因为在 monad m我们要 a -> m b表示来自 a 的有效功能至b .但是很容易适应。类型(a,s) -> (b,s)可以不加 curry 得到a -> s -> (b,s)我们采取m b成为 s -> (b,s) , 所以 a -> m b代表a -> s -> (b,s) .

所以这就是monad State s代表。对于每种类型 b类型 State s bs -> (b,s) ,可以读作“给我缺少的初始状态s,这样我就可以计算b和最终状态s。有状态函数a -> State s ba -> s -> (b,s),可以读为说“这个函数需要一个 a并产生一个给定初始状态的计算s产生结果 b和最终状态s .

这只是为了让您大致了解它的工作原理。现在这里有一些代码可以满足您的需求。让我们从一个简单的方法开始。

size :: [Int] -> State Int ()
size [] = put 0
size (x:xs) = do size xs
num <- get
put (num + 1)

类型为 State Int ()因为您只是在更新一个整数状态并且不返回任何值(我们只关心状态)。

该过程与计算大小的常用递归函数非常相似(没有累加器),但我们通过更新状态来完成工作。要运行此示例,只需执行以下操作,
runState (size list) 0 

对于一些 list .注意 0此处与初始状态无关,因为该算法通过将状态设置为 0 来工作。对于空列表,然后添加 1对于每个元素。

现在是一个以累积方式工作的版本,
sizeAc :: [Int] -> State Int ()
sizeAc [] = return ()
sizeAc (x:xs) = do num <- get
put (num + 1)
sizeAc xs

再次运行这个例子,
runState (sizeAc list) 0 

请注意,在这种情况下,您必须使用 0作为初始状态。该函数所做的是,对于列表中的每个元素,它通过将状态值加一来更新状态。对于空列表,它什么也不做。

终于有了 map 的版本,因为它出现在您最初的尝试中。首先我们实现计数 Action 。
count :: State Int ()
count = do num <- get
put (num + 1)

此操作包括访问状态并使用添加的单元对其进行更新。然后为列表中的每个元素构建一个此类操作的列表。
sizeAux'   :: [Int] -> [State Int ()]
sizeAux' xs = map (\x -> count) xs

注意结果的类型是一个列表。结果是一个列表,其中所有元素都是操作 count .然后我们使用 sequence_ 依次执行这些操作。 ,其类型如下(专门用于列表和我们特定的 monad)。
 sequence_ :: [m a] -> m ()
sequence_ :: [State Int ()] -> State Int ()

结果函数是
size'   :: [Int] -> State Int ()
size' xs = sequence_ (sizeAux' xs)

再次可以通过它运行,
runState (size' list) 0

并在这里再次注意初始状态 0是必不可少的。

在这一点上,这可能仍然有些复杂。您需要更好地理解 monad 类、do 表示法和 State monad 的特殊性。无论如何,这是您应该前进的方向,而不是将 State 与 IO 混为一谈。

关于Haskell:如何在纯函数中产生副作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53447330/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com