我查看了State monad的一些教程,我想我有了这个想法.
例如,在这个很好的教程中:
import Data.Word
type LCGState = Word32
lcg :: LCGState -> (Integer, LCGState)
lcg s0 = (output, s1)
where s1 = 1103515245 * s0 + 12345
output = fromIntegral s1 * 2^16 `div` 2^32
getRandom :: State LCGState Integer
getRandom = get >>= \s0 -> let (x,s1) = lcg s0
in put s1 >> return x
Run Code Online (Sandbox Code Playgroud)
好的,所以我可以使用getRandom:
*Main> runState getRandom 0
(0,12345)
*Main> runState getRandom 0
(0,12345)
*Main> runState getRandom 1
(16838,1103527590)
Run Code Online (Sandbox Code Playgroud)
但是我每次打电话都需要把种子传给PRNG.我知道Haskell实现中可用的PRNG不需要:
Prelude> :module Random …Run Code Online (Sandbox Code Playgroud) 所以我正在Haskell中编写一个游戏,我将玩家视为一系列与各种转弯阶段相关的状态改变函数.最初,这看起来像:
let game' = phase1 game
game'' = phase2 game'
-- etc.
Run Code Online (Sandbox Code Playgroud)
国家monadosity的主要候选人,对吧?这导致更优雅:
do
phase1
phase2
-- etc.
Run Code Online (Sandbox Code Playgroud)
然而,似乎我必须改变phase1,phase2等等以一个样板"状态获取"步骤开始:
phase1 = get >>= \game -> -- ...
Run Code Online (Sandbox Code Playgroud)
我希望有一种方法可以抽象出来,所以我可以避免调用者和被调用者都使用样板文件.我太新了,不知道这是什么方式(这是我的第一个真正的Haskell项目).有什么建议?
这是我在SO上的第一篇文章,我对Haskell相对较新,所以请原谅任何失误或者我的代码不是惯用的!
考虑以下两个直观的描述:a,f(a),f(f(a))......
A. 一个包含以下内容的列表:a,应用f到a,应用f到那个,应用f到那个 ...
B. 一个列表,在第i个位置包含嵌套的应用程序f到a.
我的问题是我试图iterate在Haskell中使用该函数来做A烧毁.我的真实应用是模拟,但下面的人为例子突出了这个问题.
import Control.Monad.State
example :: State Int [[String]]
step :: [String] -> State Int [String]
step l = do
currentState <- get
let result = if (currentState == 1)
then "foo":l
else "bar":l
put (currentState + 1)
return result
example = do
sequence $ take 3 . iterate (>>= step) $ return []
Run Code Online (Sandbox Code Playgroud)
有了这些定义,
evalState example 1
Run Code Online (Sandbox Code Playgroud)
结果是:
[[],["foo"],["bar","bar"]]
Run Code Online (Sandbox Code Playgroud)
显然,iterate不乙,没有一个!因为该 …
尽管阅读了LYAH中真正清晰的解释,然后是Haskell Wiki以及其他一些内容,我仍然对状态monad的实现方式感到困惑.虽然我不自信,但我想我明白它是什么.
所以,假设我有一些简单的数据类型:
data Simple a = Top a
deriving ( Show )
Run Code Online (Sandbox Code Playgroud)
还有这个:
newtype SimpleState a = SimpleState { applySimple :: Int -> ( a, Int ) }
Run Code Online (Sandbox Code Playgroud)
然后我将SimpleState作为monad
instance Monad SimpleState where
return x = SimpleState $ \s -> ( x, s )
st >>= g = SimpleState $ \s -> let ( x, s' ) = applySimple st s in applySimple ( g x ) s'
Run Code Online (Sandbox Code Playgroud)
问题1:lambda如何将s(状态)作为参数?它是如何传入的?
问题2:如果applySimple在其函数签名中包含一个参数,为什么我applySimple st s在lambda中?为什么要applySimple …
在下面的代码中,如何替换put 1某些在该状态下插入非确定性1或2的代码?
import Control.Monad.List
import Control.Monad.Trans.State
test :: StateT Int [] Int
test = do
put 1
v <- get
return v
Run Code Online (Sandbox Code Playgroud) monads haskell non-deterministic state-monad monad-transformers
假设我们有一堆具有状态monad变换器的monad作为最外层的变换器,如下所示:
-- | SEWT: Composition of State . Except . Writer monad transformers in that
-- order where Writer is the innermost transformer.
-- the form of the computation is: s -> (Either e (a, s), w)
newtype SEWT s e w m a = SEWT {
_runSEWT :: StateT s (ExceptT e (WriterT w m)) a }
deriving (Functor, Applicative, Monad,
MonadState s, MonadError e, MonadWriter w)
-- | 'runSEWT': runs a 'SEWT' computation given an initial state.
runSEWT …Run Code Online (Sandbox Code Playgroud) 在Haskell中,州是monad被传递以提取和存储状态.在以下两个示例中,两个都使用状态monad >>,并且密切验证(通过函数内联和缩减)确认状态确实传递到下一步.
然而,这似乎不是很直观.那么,这是否意味着,当我想通过国家单子我只需要>>(或>>=与lambda表达式\s -> a,其中s是不是免费的a)?任何人都可以为这一事实提供直观的解释,而无需减少功能吗?
-- the first example
tick :: State Int Int
tick = get >>= \n ->
put (n+1) >>
return n
-- the second example
type GameValue = Int
type GameState = (Bool, Int)
playGame' :: String -> State GameState GameValue
playGame' [] = get >>= \(on, score) -> return score
playGame' (x: xs) = get >>= \(on, score) ->
case x of
'a' | …Run Code Online (Sandbox Code Playgroud) 短版本:当我使用runMaybeT然后使用runState类型的monad时MaybeT (State <type>) (),看起来即使Maybe结果等于也没有发生状态变化Just ().为什么?
完整版:我正在编写一个程序来解决河内之塔.我将解决方案表示为Statemonad 列表,在排序时,操作初始Towers状态:
data Towers = Towers [Int] [Int] [Int]
deriving (Show)
type Move = State Towers ()
towerMoves :: Int -> Rod -> Rod -> [Move]
towerMoves 1 r1 r2 = [pop r1 >>= push r2]
towerMoves n r1 r2 = topToTemp ++ (towerMoves 1 r1 r2) ++ topToFinal
where
r3 = other r1 r2
topToTemp = towerMoves (n …Run Code Online (Sandbox Code Playgroud) 这是一个场景:给定的是一个C库,其核心是一些结构,其中的操作由丰富的C函数提供.
第1步:使用Haskell的FFI创建一个包装器.它具有像myCLibInit :: IO MyCLibObj,myCLibOp1 :: MyCLibObj -> ... -> IO ()等等功能.MyCLibObj是一个opaque类型,它携带(和隐藏)一个Ptr或ForeignPtr实际的C结构,例如,如本维基或RWH ch中所示.17.
第2步:使用unsafeIOToST从Control.Monad.ST.Unsafe将所有IO操作转换为ST操作.这是通过引入类似的东西来完成的
data STMyCLib s = STMyCLib MyCLibObj
Run Code Online (Sandbox Code Playgroud)
然后将所有IO函数包装在ST函数中,例如:
myCLibInit' :: ST s (STMyCLib s)
myCLibInit' = unsafeIOToST $ STMyCLib <$> myCLibInit
Run Code Online (Sandbox Code Playgroud)
这允许编写命令式程序,这些程序反映了类似OO的C库的使用,例如:
doSomething :: ST s Bool
doSomething = do
obj1 <- myCLibInit'
success1 <- myCLibOp1' obj1 …Run Code Online (Sandbox Code Playgroud) 在设计编程模型时,我总是会遇到哪种方法更好的难题:
type MyMonad1 = StateT MyState (Reader Env)
type MyMonad2 = ReaderT Env (State MyState)
Run Code Online (Sandbox Code Playgroud)
在使用一个单子与另一个单子之间有什么好处和取舍?有关系吗?性能如何?
haskell ×10
state-monad ×10
monads ×7
abstraction ×1
boilerplate ×1
ffi ×1
iteration ×1
loops ×1
performance ×1
reader-monad ×1
st-monad ×1