标签: st-monad

Haskell - 双重人格IO/ST monad?

我有一些代码目前使用ST monad进行评估.我不喜欢将IO放在任何地方,因为该runST方法产生纯粹的结果,并指示这样的结果可以安全地调用(相对unsafePerformIO).但是,由于我的一些代码变得更长,我确实希望将调试打印语句放入.

是否有任何类提供双重个性monad [或类型类机制],可以是ST或IO(取决于其类型或"isDebug"标志)?我记得SPJ在他的"Fun with Type Functions"论文中引入了一个"Mutation"类,它使用关联类型将IO与IORef和ST关联到STRef.这样的包存在某个地方吗?

编辑/解决方案

非常感谢[第n次],CA McCann!使用该解决方案,我能够为支持pdebug函数的monad引入一个额外的类.该ST单子会忽略这些呼叫,而IO将运行putStrLn.

class DebugMonad m where
    pdebug :: String -> m ()

instance DebugMonad (ST s) where
    pdebug _ = return ()

instance DebugMonad IO where
    pdebug = putStrLn

test initV = do
    v <- newRef initV
    modifyRef v (+1)
    pdebug "debug"
    readRef v
testR v = runST $ test v
Run Code Online (Sandbox Code Playgroud)

这在ghci中有一个非常幸运的结果.由于默认情况下表达式是IO类型,因此运行类似"test 3"的操作将导致IO monad运行,因此您可以轻松地调试它,然后在您真正想要运行时使用类似"testR"的方法调用它它.

monads haskell io-monad st-monad

18
推荐指数
2
解决办法
1380
查看次数

有没有证据证明runST确实是纯粹的?

最初由Launchbury和Peyton Jones设计的ST monad允许Haskell程序员编写命令式代码(使用可变变量,数组等),同时获得该代码的纯接口.

更具体地说,入口点函数的多态类型

runST :: (forall s. ST s a) -> a
Run Code Online (Sandbox Code Playgroud)

确保ST包含计算的所有副作用,并且结果值是纯的.

这是否经过严格(甚至正式)证明?

haskell proof st-monad semantics

12
推荐指数
2
解决办法
379
查看次数

在Agda建模ST monad

这个最近的SO问题促使我在Haskell中编写了一个不安全且纯粹的ST monad仿真,这是一个稍微修改过的版本,你可以在下面看到:

{-# LANGUAGE DeriveFunctor, GeneralizedNewtypeDeriving, RankNTypes #-}

import Control.Monad.Trans.State
import GHC.Prim (Any)
import Unsafe.Coerce (unsafeCoerce)
import Data.List

newtype ST s a = ST (State ([Any], Int) a) deriving (Functor, Applicative, Monad)
newtype STRef s a = STRef Int deriving Show

newSTRef :: a -> ST s (STRef s a)
newSTRef a = ST $ do
  (env, i) <- get
  put (unsafeCoerce a : env, i + 1)
  pure (STRef i)

update :: [a] -> (a -> a) …
Run Code Online (Sandbox Code Playgroud)

haskell agda st-monad

11
推荐指数
1
解决办法
420
查看次数

这种签名发生了什么?(Haskell中的Vector.Mutable修饰符)

Haskell中的可变载体有三个元素级变异器:

read :: PrimMonad m => MVector (PrimState m) a -> Int -> m a
write :: PrimMonad m => MVector (PrimState m) a -> Int -> a -> m ()
swap :: PrimMonad m => MVector (PrimState m) a -> Int -> Int -> m ()
Run Code Online (Sandbox Code Playgroud)

现在我可以使用这些 -

import Data.Vector
import Data.Vector.Mutable 
import Control.Monad.ST
import Control.Monad.Primitive 

incrAt :: Vector Double -> Int -> Vector Double
incrAt vec i = runST $ do
  mvec <- thaw vec
  oldval <- read …
Run Code Online (Sandbox Code Playgroud)

haskell typeclass type-signature io-monad st-monad

10
推荐指数
1
解决办法
767
查看次数

如何将可变向量放入状态Monad

我在haskell中编写了一个小程序,使用State Monad with Vector计算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 …
Run Code Online (Sandbox Code Playgroud)

monads haskell state-monad monad-transformers st-monad

8
推荐指数
1
解决办法
1128
查看次数

ST monad声明的语法

我最近开始在Hackage上查看核心库,并且有一个我不理解的反复出现的习惯用法.以下是ST模块的示例:

instance Monad (ST s) where
    {-# INLINE (>>=)  #-}
    (>>) = (*>)
    (ST m) >>= k
      = ST (\ s ->
        case (m s) of { (# new_s, r #) ->
        case (k r) of { ST k2 ->
        (k2 new_s) }})
Run Code Online (Sandbox Code Playgroud)

特别是,我不明白(# new_s, r #).我假设第二个哈希是指一个未装箱的值,但其余的对我来说是一个谜(大概与"新状态"有关).

haskell st-monad

8
推荐指数
1
解决办法
77
查看次数

用于在地图上进行插入和总查找的Monad转换器?

我有一个计算,我在其中将值插入Map,然后再次查找它们。我知道我从来没有在插入密钥之前使用过密钥,但是(!)无论如何随意使用都会使我感到紧张。我正在寻找一种获取总查询功能的方法,该方法不会返回Maybe,并且类型系统可以防止我意外滥用。

我的第一个想法是制作一个类似于的monad转换器StateT,其中状态为a Map,并且在monad中有用于插入和查找的特殊功能。插入函数返回一个新类型Receipt s k,其中sSTmonad 样式的幻像索引类型,并且k是键的类型,而查找函数则使用a Receipt而不是裸键。通过隐藏Receipt构造函数并使用类似于的量化运行函数runST,这应确保查找仅在插入同一映射后发生。(完整代码如下。)

但是我担心我已经重新发明了轮子,或者担心有另外一种获取安全的总地图查找的方法。在某个地方的公共包装中是否存在针对此问题的任何现有技术?

{-# LANGUAGE DeriveFunctor, LambdaCase, RankNTypes #-}

module KeyedStateT (KeyedStateT, Receipt, insert, lookup, receiptToKey, runKeyedStateT)
where

import Prelude hiding (lookup)
import Control.Arrow ((&&&))
import Control.Monad (ap, (>=>))
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromJust)

newtype KeyedStateT s k v m a = KeyedStateT (Map k v -> …
Run Code Online (Sandbox Code Playgroud)

dictionary haskell state-monad monad-transformers st-monad

6
推荐指数
1
解决办法
137
查看次数

在 Haskell 中结合 ST 和 List monad

使用StateTmonad 转换器,我可以创建与StateT s [] a同构的类型s -> [(a, s)]。现在我更喜欢使用STTmonad 转换器,因为我想要多个不同类型的可变变量,并且希望能够根据早期计算的结果随意实例化它们。

但是,STT明确提及的链接文档:

这个 monad 转换器不应该与可以包含多个答案的 monad 一起使用,比如列表 monad。原因是状态标记将在不同的答案中重复,这会导致坏事发生(例如失去参考透明度)。安全的 monad 包括 monads State、Reader、Writer、Maybe 以及它们对应的 monad 转换器的组合。

那么我的选择是什么?

完全清楚:

  • 我所追求的是非确定性。我希望能够分叉我的计算,为每个分支提供自己的整个状态副本。
  • 我不太介意并行性,因为性能不是我最关心的问题。
  • 追求的是并发:不同的计算分支不应共享可变变量;相反,他们都应该处理他们自己的原始可变变量的副本。

编辑:(编辑编辑:下面的反例是无效的,因为ListT不应该应用于非可交换的 monadSTState。)我开始意识到按照 的方式STT行事的monad 转换器StateT本质上是不安全的。有了它,我们可以构建一个类型STT sloc (ListT (ST sglob)) a。这里,sglob是全局状态sloc的名称,而是局部状态的名称。* 现在我们可以使用全局状态在线程之间交换局部状态引用,从而潜在地获得对未初始化变量的引用。

*为了比较,对应的StateT构造是StateT sloc (ListT (State sglob)) a,与 同构sloc -> …

haskell non-deterministic state-monad st-monad

5
推荐指数
1
解决办法
310
查看次数

将ST monad重新装扮成类似于州Monad的东西

这是一个场景:给定的是一个C库,其核心是一些结构,其中的操作由丰富的C函数提供.

第1步:使用Haskell的FFI创建一个包装器.它具有像myCLibInit :: IO MyCLibObj,myCLibOp1 :: MyCLibObj -> ... -> IO ()等等功能.MyCLibObj是一个opaque类型,它携带(和隐藏)一个PtrForeignPtr实际的C结构,例如,如本维基RWH ch中所示.17.

第2步:使用unsafeIOToSTControl.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)

haskell ffi state-monad st-monad

4
推荐指数
1
解决办法
93
查看次数

Data.Vector的unsafeFreeze/unsafeThaw有多"不安全"?

对文件Data.Vector.unsafeFreeze说:

不安全[ly]将可变向量转换为不可变向量而不进行复制.在此操作之后可能不使用可变载体.

我想详细描述这里"不安全"的含义.在实验上,它似乎"仅"意味着对原始可变载体的进一步修改将导致返回的不可变向量unsafeFreeze不再是纯的:

$ import qualified Data.Vector as V
$ import qualified Data.Vector.Mutable as MV
$ import Control.Monad.ST
$ :{
$ |runST $ do
$ |        mv <- V.thaw $ V.fromList [0..10]
$ |        v <- V.unsafeFreeze mv
$ |        MV.write mv 0 (-1)
$ |        MV.write mv 1 (-2)
$ |        v' <- V.freeze mv
$ |        v'' <- V.unsafeFreeze mv
$ |        return (v, v', v'')
$ |:}
([-1,-2,2,3,4,5,6,7,8,9,10],[-1,-2,2,3,4,5,6,7,8,9,10],[-1,-2,2,3,4,5,6,7,8,9,10])
Run Code Online (Sandbox Code Playgroud)

我可以想象一个修改"不安全"冻结中使用的来源做各种粗糙的事情会导致更糟糕的行为,例如segfaulting.不幸的是,我很快就忘记了尝试阅读不安全操作的来源.

我可以依靠所说的杂质是这些操作"不安全"的唯一方式吗?

对于上下文:我需要在一个通常不可变的数据结构上实现各种修改算法,而不是在内部可变性范围内重用其面向公众的API会非常不方便(因为AFAICT没有办法一般地访问 …

haskell st-monad

4
推荐指数
1
解决办法
183
查看次数

Haskell ST Monad:没有 (MArray (STArray s) Int (ST s1)) 的实例

我最近一两个月一直在学习Haskell,最近解决了这个编码问题。额外的挑战是在没有额外空间和线性时间内完成任务,我认为这不可能以纯函数的方式完成,所以很自然地我发现了 ST monad,我认为这将是一个很好的机会了解更多信息。不管怎样,这是我写的代码:

\n\n
module FindDuplicates where\n\nimport Control.Monad (foldM)\nimport Control.Monad.ST\nimport Data.Array.ST\n\nxs = [4,3,2,7,8,2,3,1] :: [Int]\n\nfindDuplicates :: [Int] -> ST s [Int]\nfindDuplicates xs = do\n    arr <- newListArray (1, length xs) xs :: ST s (STArray s Int Int)\n\n    let go :: [Int] -> Int -> ST s [Int]\n        go acc i = do x <- abs <$> readArray arr i\n                      y <- readArray arr x\n                      if y < 0\n                          then return (x:acc)\n                          else do writeArray arr x (-y)\n …
Run Code Online (Sandbox Code Playgroud)

monads haskell starray st-monad

3
推荐指数
1
解决办法
362
查看次数