我想让我的一些代码更“monadic”并使用Reader monad而不是传递一个共同的环境。但在某些地方我必须使用可变矢量,因此ST monad也是如此;为了让事情变得有趣,ST动作需要访问环境(但其余的功能却没有)。换句话说,这有效:
aux :: Int -> Reader Env Double
aux i = -- something
bla :: [a] -> Reader Env Double
bla l = do e <- ask
return $ runST $ do -- something producing an Int
let o = runReader (aux i) e
-- something else depending on o
return something
但感觉非常丑陋和错误,是一种令人费解的方式仍然明确地传递环境;我希望bla
看起来更像这样:
bla :: [a] -> Reader Env Double
bla l = return $ runST $ do -- something producing an Int
o <- ??? aux i
-- something depending on o
return something
有意义吗?可能吗?如果是,我必须代替???
放置什么?我想真正的问题是,实现这种事情的好方法是什么?你会推荐什么设计?
答案 0 :(得分:4)
您可以使用Reader
将ST
与ReaderT
混合使用。这样的事情:
import Data.Array.ST
import Control.Monad.ST
import Control.Monad.Reader
type Env = String
type ReaderST s = ReaderT Env (ST s)
foo :: ReaderST s [Int]
foo = do
str <- ask
let len = length str
a <- lift (newArray (0, len - 1) 0 :: ST s (STUArray s Int Int))
a' <- lift $ mapArray (+ 2) a
es <- lift $ getElems a'
return es
run :: [Int]
run = runST $ runReaderT foo "xyz"
-- > run
-- [2,2,2]
答案 1 :(得分:1)
你能否使用ReaderT
monad变换器并将其堆叠在ST
之上?就像这里:http://book.realworldhaskell.org/read/monad-transformers.html