gpt4 book ai didi

haskell - 如何将可变向量放入状态单子(monad)

转载 作者:行者123 更新时间:2023-12-04 06:02:54 25 4
gpt4 key购买 nike

我在 haskell 中编写了一个小程序,使用带有 Vector 的 State Monad 来计算 Tree 中所有 Int 值的出现次数:

import Data.Vector
import Control.Monad.State
import Control.Monad.Identity

data Tree a = Null | Node (Tree a) a (Tree a) deriving Show
main :: IO ()
main = do
print $ runTraverse (Node Null 5 Null)


type MyMon a = StateT (Vector Int) Identity a

runTraverse :: Tree Int -> ((),Vector Int)
runTraverse t = runIdentity (runStateT (traverse t) (Data.Vector.replicate 7 0))

traverse :: Tree Int -> MyMon ()
traverse Null = return ()
traverse (Node l v r) = do
s <- get
put (s // [(v, (s ! v) + 1)]) -- s[v] := s[v] + 1
traverse l
traverse r
return ()

但是不可变向量的“更新”是以 O(n) 复杂度完成的。
我正在寻找 O(1) 中的更新和 O(1) 中的访问。
据我了解,可变向量做我想做的事。要使用它们,我需要使用 ST 或 IO。
因为我想做一些单元测试,所以我更喜欢 ST monad,但我不想在函数调用中传递那个向量。
我需要继续使用 Monad Transformers,因为我将添加像 ErrorT 和 WriterT 这样的转换器。

问题:如何使用 Monad Transformers 将可变向量放入 State Monad?

我想出了以下无法编译的代码:
import Data.Vector
import Control.Monad.State
import Control.Monad.Identity
import qualified Data.Vector.Mutable as VM
import Control.Monad.ST
import Control.Monad.ST.Trans
type MyMon2 s a = StateT (VM.MVector s Int) (STT s Identity) a

data Tree a = Null | Node (Tree a) a (Tree a) deriving Show
main :: IO ()
main = do
print $ runTraverse (Node Null 5 Null)

runTraverse :: Tree Int -> ((),Vector Int)
runTraverse t = runIdentity (Control.Monad.ST.Trans.runST $ do
emp <- VM.replicate 7 0
(_,x) <- (runStateT (traverse t) emp)
v <- Data.Vector.freeze x
return ((), v)
)
traverse :: Tree Int -> MyMon2 s ()
traverse Null = return ()
traverse (Node l v r) = do
d <- get
a <- (VM.read d v)
VM.write d v (a + 1)
put d
return ()

编译错误是:
TranformersExample: line 16, column 16:
Couldn't match type `s'
with `primitive-0.5.2.1:Control.Monad.Primitive.PrimState
(STT s Identity)'
`s' is a rigid type variable bound by
a type expected by the context: STT s Identity ((), Vector Int)
at test/ExecutingTest.hs:15:30
Expected type: STT s Identity (MVector s Int)
Actual type: STT
s
Identity
(MVector
(primitive-0.5.2.1:Control.Monad.Primitive.PrimState
(STT s Identity))
Int)
In the return type of a call of `VM.new'
In a stmt of a 'do' block: emp <- VM.new 7
In the second argument of `($)', namely
`do { emp <- VM.new 7;
(_, x) <- (runStateT (traverse t) emp);
v <- freeze x;
return ((), v) }'
TranformersExample: line 26, column 14:
Couldn't match type `s'
with `primitive-0.5.2.1:Control.Monad.Primitive.PrimState
(StateT (MVector s Int) (STT s Identity))'
`s' is a rigid type variable bound by
the type signature for traverse :: Tree Int -> MyMon2 s ()
at test/ExecutingTest.hs:21:13
Expected type: MVector
(primitive-0.5.2.1:Control.Monad.Primitive.PrimState
(StateT (MVector s Int) (STT s Identity)))
Int
Actual type: MVector s Int
In the first argument of `VM.write', namely `d'
In a stmt of a 'do' block: VM.write d v (a + 1)
In the expression:
do { d <- get;
a <- (VM.read d v);
VM.write d v (a + 1);
put d;
.... }

注意:我知道不检查边界。

最佳答案

使用 ST 时声明你从来没有明确地传递向量(它总是隐藏在 s 参数中),而是对它的引用。该引用是不可变的,不会被复制,所以你不需要 State但只是一个读者隐含地传递它。

import Data.Vector
import Control.Monad.Reader
import qualified Data.Vector.Mutable as VM
import Control.Monad.ST

type MyMon3 s = ReaderT (VM.MVector s Int) (ST s)

data Tree a = Null | Node (Tree a) a (Tree a) deriving Show
main :: IO ()
main = do
print $ runTraverse (Node Null 5 Null)

runTraverse :: Tree Int -> Vector Int
runTraverse t = runST $ do
emp <- VM.replicate 7 0
runReaderT (traverse t) emp
Data.Vector.freeze emp

traverse :: Tree Int -> MyMon3 s ()
traverse Null = return ()
traverse (Node l v r) = do
d <- ask
a <- lift $ VM.read d v
lift $ VM.write d v (a + 1)

关于haskell - 如何将可变向量放入状态单子(monad),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23579959/

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