我正在尝试创建一堆monad变换器,并且无法为我的函数获取正确的类型签名.(我对Haskell还很新)
该堆栈结合了多个StateT变换器,因为我有多个状态需要跟踪(其中两个可能是tupled,但我会在一秒内完成)和一个WriterT用于记录.
这是我到目前为止所拥有的:
module Pass1 where
import Control.Monad.Identity
import Control.Monad.State
import Control.Monad.Writer
import Data.Maybe
import qualified Data.Map as Map
import Types
data Msg = Error String
| Warning String
type Pass1 a = WriterT [Msg] (StateT Int (StateT [Line] (StateT [Address] Identity))) a
runPass1 addrs instrs msgs = runIdentity (runStateT (runStateT (runStateT (runWriterT msgs) 1) instrs) addrs)
--popLine :: (MonadState s m) => m (Maybe s)
--popLine :: (Monad m) => StateT [Line] m (Maybe Line)
popLine :: (MonadState s …Run Code Online (Sandbox Code Playgroud) 我有一个类型的绑定[ST s (Int, [Int])],我试图runST使用map 应用于每个元素,如下所示:
name :: [ST s (Int, [Int])] --Of Course there is a real value here
map runST name
Run Code Online (Sandbox Code Playgroud)
这给了我一个错误信息
Couldn't match expected type `forall s. ST s b0'
with actual type `ST s0 (Int, [Int])'
Expected type: [forall s. ST s b0]
Actual type: [ST s0 (Int, [Int])]
In the second argument of `map', namely `name'
In the expression: map runST name
Run Code Online (Sandbox Code Playgroud)
必须有一些我误解的东西.我知道runST和函数组成,但我不确定这是否适用.
谢谢大家的时间!
假设我有一个状态monad,我想对状态进行一些操作,并且可能希望在将来撤消更改.我一般可以这样做得体面吗?
举一个具体的例子,让我们假设状态只是一个Int,操作就是将数字增加一个.
type TestM a = StateT a IO ()
inc :: TestM Int
inc = modify (+ 1)
Run Code Online (Sandbox Code Playgroud)
但是,如果我想跟踪状态的所有历史记录,以防我想要撤消到某个先前的状态,我能想到的最好的方法是将状态包装在堆栈中:对状态的每次修改都会被推送到堆栈,以便我可以通过删除堆栈上的顶部元素来撤消更改.
-- just for showing what's going on
traceState :: (MonadIO m, MonadState s m, Show s) => m a -> m a
traceState m = get >>= liftIO . print >> m
recordDo :: TestM a -> TestM [a]
recordDo m = do
x <- gets head
y <- liftIO $ execStateT m x
modify (y:)
inc' :: …Run Code Online (Sandbox Code Playgroud) 我正在编写一个Haskell程序,它涉及模拟一个抽象机器,它具有内部状态,接受输入并提供输出.我知道如何使用状态monad实现这一点,从而产生更清晰,更易于管理的代码.
我的问题是,当我有两个(或更多)有状态对象相互交互时,我不知道如何使用相同的技巧.下面我给出了一个高度简化的问题版本,并勾勒出我到目前为止的内容.
为了这个问题,让我们假设一个机器的内部状态只包含一个整数寄存器,因此它的数据类型是
data Machine = Register Int
deriving (Show)
Run Code Online (Sandbox Code Playgroud)
(实际的机器可能有多个寄存器,程序指针,调用堆栈等等,但现在不要担心.)在上一个问题之后我知道如何使用状态monad实现机器,所以我不必显式传递其内部状态.在这个简化的示例中,导入后实现如下所示Control.Monad.State.Lazy:
addToState :: Int -> State Machine ()
addToState i = do
(Register x) <- get
put $ Register (x + i)
getValue :: State Machine Int
getValue = do
(Register i) <- get
return i
Run Code Online (Sandbox Code Playgroud)
这让我可以写出类似的东西
program :: State Machine Int
program = do
addToState 6
addToState (-4)
getValue
runProgram = evalState program (Register 0)
Run Code Online (Sandbox Code Playgroud)
这会将6添加到寄存器,然后减去4,然后返回结果.状态monad跟踪机器的内部状态,以便"程序"代码不必明确跟踪它.
在命令式语言的面向对象样式中,这个"程序"代码可能看起来像
def runProgram(machine):
machine.addToState(6)
machine.addToState(-4)
return machine.getValue()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果我想模拟两台彼此交互的机器,我可能会写
def …Run Code Online (Sandbox Code Playgroud) 严格的状态monad定义使用:
m >>= k = State $ \s ->
case runState m s of
(a, s') -> runState (k a) s'
Run Code Online (Sandbox Code Playgroud)
但这仍然会泄漏记忆,因为a并且没有s'得到评估.例如,我们可能有一个函数f将大对象作为输入并快速返回(a, s'),但只要a没有评估,输入f就不能被GC.
一个可能的解决方案是f返回seq a (a, s'),但如果我们使用类似的东西MonadRandom,这并不总是可能的,并且状态被封装起来f.是否有这样定义的版本:
m >>= k = State $ \s ->
case runState m s of
(!a, !s') -> runState (k a) s'
Run Code Online (Sandbox Code Playgroud)
这已存在于任何地方的图书馆吗?
我有一个功能:
test :: String -> State String String
test x =
get >>= \test ->
let test' = x ++ test in
put test' >>
get >>= \test2 -> put (test2 ++ x) >>
return "test"
Run Code Online (Sandbox Code Playgroud)
我几乎可以理解整个函数中发生了什么,并且我开始得到monad的支持.我不明白的是,当我这样做时:
runState (test "testy") "testtest"
Run Code Online (Sandbox Code Playgroud)
'test'中的'get'函数以某种方式获得初始状态"testtest".有人可以打破这个并向我解释一下吗?
我感谢任何回应!
对于我在Haskell中的矢量图形库,我必须携带一个相当大的状态:线条描边参数,颜色,剪辑路径等.我知道两种方法.引用Haskell-cafe的评论:"我建议你使用具有可变状态的读取器monad,或者使用具有不可变状态的状态monad".
这是我的问题:更新一个大的不可变状态是一个性能杀戮.使用大量的STRef就像在Haskell中编写C一样:它冗长而丑陋.
这是不可变状态:
data GfxState = GfxState {
lineWidth :: Double,
lineCap :: Int,
color :: Color,
clip :: Path,
...
}
setLineWidth :: Double -> State GfxState ()
setLineWidth x = modify (\state -> state { lineWidth = x })
Run Code Online (Sandbox Code Playgroud)
据我所知,"state {lineWidth = x}"创建一个新的GfxState并让旧的GfxState被垃圾收集.当状态很大并经常更新时,这会导致性能下降.
这是可变状态:
data GfxState s = GfxState {
lineWidth :: STRef s Double,
lineCap :: STRef s Int,
color :: STRef s Color,
clip :: STRef s Path,
...
many more STRefs
}
setLineWidth …Run Code Online (Sandbox Code Playgroud) 我如何State用来模仿行为List.zipWithIndex?到目前为止我提出的(不起作用)是:
def numberSA[A](list : List[A]) : State[Int, List[(A, Int)]] = list match {
case x :: xs => (init[Int] <* modify((_:Int) + 1)) map { s : Int => (x -> s) :: (numberSA(xs) ! s) }
case Nil => state( (i : Int) => i -> nil[(A, Int)] )
}
Run Code Online (Sandbox Code Playgroud)
这基于状态示例非常松散.正如我所说,它不起作用:
scala> res4
res5: List[java.lang.String] = List(one, two, three)
scala> numberSA(res4) ! 1
res6: List[(String, Int)] = List((one,1), (two,1), (three,1))
Run Code Online (Sandbox Code Playgroud)
我可以通过更改case语句的一行来使它工作:
case x …Run Code Online (Sandbox Code Playgroud) 我是一名JavaScript开发人员,可以提升我在函数式编程方面的技能.在管理国家时,我最近碰到了一堵墙.在搜索解决方案时,我在各种文章和视频中对状态monad进行了标记,但我很难理解它.我想知道是不是因为我希望它不是.
在Web客户端中,我从后端获取资源.为了避免不必要的流量,我在客户端创建一个包含已经获取的数据的简单缓存.缓存是我的状态.我希望我的几个模块能够保存对缓存的引用并查询它的当前状态,这个状态可能已被另一个模块修改过.
这当然不是javascript中的问题,因为它可以改变状态,但我想学习更多关于函数式编程的知识,我希望状态monad会帮助我.
我以为我可以这样做:
var state = State.of(1);
map(add(1), state);
state.evalState() // => 2
Run Code Online (Sandbox Code Playgroud)
这显然不起作用.国家总是1.
我对状态monad的假设是错误的,还是我只是错误地使用它?
我意识到我可以这样做:
var state = State.of(1);
var newState = map(add(1), state);
Run Code Online (Sandbox Code Playgroud)
...并且newState将是2的状态.但是在这里我并没有真正看到状态monad的使用,因为我将不得不创建一个新实例以便更改值.这对我来说似乎总是在函数式编程中完成,其中值是不可变的.
在GHC.IO中,差异和预期用途有何用途ioToST和unsafeSTToIO定义?
-- ---------------------------------------------------------------------------
-- Coercions between IO and ST
-- | A monad transformer embedding strict state transformers in the 'IO'
-- monad. The 'RealWorld' parameter indicates that the internal state
-- used by the 'ST' computation is a special one supplied by the 'IO'
-- monad, and thus distinct from those used by invocations of 'runST'.
stToIO :: ST RealWorld a -> IO a
stToIO (ST m) = IO m
ioToST :: IO …Run Code Online (Sandbox Code Playgroud) state-monad ×10
haskell ×8
monads ×3
ghc ×1
haskell-lens ×1
io ×1
lenses ×1
scala ×1
scalaz ×1
types ×1