Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 具有多个状态值的状态单子_Haskell_Monads_State Monad - Fatal编程技术网

Haskell 具有多个状态值的状态单子

Haskell 具有多个状态值的状态单子,haskell,monads,state-monad,Haskell,Monads,State Monad,考虑以下几点: do x1 <- new 2 set x1 3 x2 <- get x1 y1 <- new 10 set y1 20 y2 <- get y1 return (x2 + y2) do x1在Control.Monad.State中已经有一个实现,但出于通用性的考虑,它很麻烦:一个复杂因素来自MonadState类,另一个复杂因素来自普通状态是根据更通用的状态实现的 下面是一个使用该实现的任务示例。没有使用可变性。请注意,您的

考虑以下几点:

do
  x1 <- new 2
  set x1 3
  x2 <- get x1
  y1 <- new 10
  set y1 20
  y2 <- get y1
  return (x2 + y2)
do

x1在
Control.Monad.State
中已经有一个实现,但出于通用性的考虑,它很麻烦:一个复杂因素来自MonadState类,另一个复杂因素来自普通
状态
是根据更通用的
状态
实现的

下面是一个使用该实现的任务示例。没有使用可变性。请注意,您的示例按原样粘贴,只是添加了
x
前缀:

import Control.Monad.State
import qualified Data.Map as M

type MyMap a = M.Map Int a
type MyState a b = State (MyMap a) b
type MyRef = Int

xrun :: MyState a b -> b
xrun x = evalState x (M.empty)

mget :: MyState a (MyMap a)
mget = get

mput :: MyMap a -> MyState a ()
mput = put

mmodify :: (MyMap a -> MyMap a) -> MyState a ()
mmodify x = modify x

xnew :: s -> MyState s MyRef
xnew val = do
    s <- mget
    let newRef = if M.null s then 0 else fst (M.findMax s) + 1
    mput $ M.insert newRef val s
    return newRef

xset :: MyRef -> a -> MyState a () 
xset ref val = modify $ M.insert ref val

xget :: MyRef -> MyState a a
xget ref = fmap (\s -> case M.lookup ref s of Just v -> v) get

test :: MyState Int Int
test = do
  x1 <- xnew 2
  xset x1 3
  x2 <- xget x1
  y1 <- xnew 10
  xset y1 20
  y2 <- xget y1
  return (x2 + y2)

main = print $ xrun test

将其保存到
MyState.hs
并将
import Control.Monad.State
替换为
import MyState
,替换为
State
StateT
您可以模拟它(
State
仅允许1个值)。最简单的方法是使用
Map

 do
  put empty
  set "x1" 3  
  x2 <-  getKey "x1"
  set "y1" 20
  y2 <-  getKey "y1"
  return (x2 + y2)
    where
      getKey k = fromJust . (lookup k) `fmap` get
      set = modify replace
      replace d k m = if k `member` m then update (\_ -> Just d) k m
                      else insert k d m
do
空置
将“x1”设置为3

x2这允许一个以上的值,但它更复杂:)丹尼尔的
Dynamic
建议很好地简化了这一点

import Data.Dynamic
import Data.Maybe
import Control.Monad.State
import Data.Map as M

newtype Ref a = Ref {ref :: Int}

type MutState = State (Int, Map Int Dynamic)

val :: Typeable a => Ref a -> MutState a
val r = snd `fmap` get >>= 
        return . fromJust . (>>= fromDynamic) .  M.lookup (ref r)

new :: Typeable a => a -> MutState (Ref a)
new a = do
  (curr, binds) <- get
  put (curr + 1, M.insert (curr + 1) (toDyn a) binds)
  return . Ref $ curr + 1

set :: Typeable a => Ref a -> a -> MutState ()
set (Ref i) a = do
  (c, m) <- get
  put (c, M.insert i (toDyn a) m)

runMut :: MutState a -> a
runMut = flip evalState (0, M.fromList [])
导入数据。动态
导入数据,也许吧
进口控制单体状态
导入数据。映射为M
新类型Ref a=Ref{Ref::Int}
类型MutState=State(Int,Map Int动态)
val::Typeable a=>Ref a->MutState a
val r=snd`fmap`get>>=
返回。从刚才开始。(>>=fromDynamic)。M.查找(参考r)
新::可键入a=>a->MutState(参考a)
新a=do
(当前,绑定)参考a->a->MutState()
设置(参考i)a=do
(c,m)a
runMut=flip evalState(0,M.fromList[])
然后使用它

default (Int) -- too lazy for signatures :)
test :: Int
test = runMut $ do
  x1 <- new 2
  set x1 3
  x2 <- val x1
  y1 <- new 10
  set y1 20
  y2 <- val y1
  return (x2 + y2)
default(Int)--签名太懒:)
测试::Int
test=runMut$do

一个元组的StateT如何

flip evalState (2, 10) $ do
  modify $ \(_, y) -> (3, y)
  x2 <- fst <$> get
  modify $ \(x, _) -> (x, 20)
  y2 <- snd <$> get
  return (x2 + y2)
flip evalState(2,10)$do
修改$\(\,y)->(3,y)
x2(x,20)

y2是关于实现可变引用的问题,还是您还需要学习如何实现纯状态monad?纯状态。不需要实际的可变实现。如果这已经存在一个链接到黑客网页将是罚款。这样做的问题是:一个人似乎能够
将整个状态,而不是代码中的特定“变量”
x1
y1
似乎是变量,而
x2
y2
似乎是值;这些将有不同的类型,所以我觉得命名令人惊讶。你知道吗?我不知道,但我明白你的意思。这个名字很普通,但我现在不会改变。不知道你说的普通是什么意思。在Haskell中,
Integer
类型的变量与某些状态下的命名引用完全不同;我真的建议不要给出令人困惑的名字。我首先也得到了答案(被我否决,然后被我删除),但如果你仔细观察,你会发现克林顿想要跟踪该州的变量,而不仅仅是一个州,所以类似于
ST
monad。我认为类似于
键入MyState a b=state(M.Map Int a,Int)b将为他做这项工作。我现在正在详细说明答案,这就是我在下面写的。请注意,您不需要第二个Int,您可以轻松(高效)获得映射中的最大索引。“我知道我说过我不担心效率,但那似乎有点像黑客。”克林顿,如果你有200。。价值观,这是没有效率的。这只是
O(logn)
为什么要重新实现?@DanielWagner,谢谢!你知道吗,有一天我会发布一个答案,而你不会发布一条评论,说明它是多么不必要地过于复杂;)有趣的是,
\(\uu,y)->(3,y)
(first.const)3
相同。
flip evalState (2, 10) $ do
  modify $ \(_, y) -> (3, y)
  x2 <- fst <$> get
  modify $ \(x, _) -> (x, 20)
  y2 <- snd <$> get
  return (x2 + y2)