我正在阅读真实世界哈斯克尔 - 第10章.
所有函数都有共同类型L.ByteString -> Maybe (a, L.ByteString)
所以然后我查看了StateT定义,s -> m (a, s)如果它被写入,它与上面的内容完全匹配StateT L.ByteString Maybe a.所以我决定使用monad变换器重写第一个例子.希望如此
parseP5 :: StateT L.ByteString Maybe Greymap
parseP5 = do
matchHeader (L8.pack "P5")
skipSpace
width <- getNat
skipSpace
height <- getNat
skipSpace
maxGrey <- getNat
skipSpace
_ <- getBytes 1
bitmap <- getBytes (width*height)
return (Greymap width height maxGrey bitmap)
Run Code Online (Sandbox Code Playgroud)
会工作的.
例如,matchHeader功能将成为
matchHeader :: L.ByteString -> StateT L.ByteString Maybe ()
matchHeader prefix = \str ->
if …Run Code Online (Sandbox Code Playgroud) 已经讨论过,mapM这里本来就不是懒惰的,例如这里和这里.现在我正在努力解决这个问题的变化,其中mapM问题是在monad变换器堆栈内部.
这是一个函数,它取自我在gist.github.com上使用的LevelDB的具体,工作(但是空间泄漏)的例子:
-- read keys [1..n] from db at DirName and check that the values are correct
doRead :: FilePath -> Int -> IO ()
doRead dirName n = do
success <- runResourceT $ do
db <- open dirName defaultOptions{ cacheSize= 2048 }
let check' = check db def in -- is an Int -> ResourceT IO Bool
and <$> mapM check' [1..n] -- space leak !!!
putStrLn $ if …Run Code Online (Sandbox Code Playgroud) 我想编写一种可以通过其 monad 转换器参数化的类型。我尝试了几件事,最终得到了一些类似的东西:
newtype Foo t a = Foo { unFoo :: t (State St) a }
Run Code Online (Sandbox Code Playgroud)
然后,我想要一堆实例:
deriving instance (MonadTrans t, Monad (t (State St))) => Monad (Foo t)
Run Code Online (Sandbox Code Playgroud)
最后,我使用适当的 monad 转换器实例化类型。我的代码类型检查,但我收到所有派生实例的警告:“没有明确的实现>>=”。如果我尝试运行它,当它遇到类型类函数时会出现未定义的错误。
有没有办法自动派生我需要的所有实例?我试图派生出更多的类,而不仅仅是Monad.
我也对一种更符合人体工程学的方式来完成同样的事情感兴趣——我必须不断手动包装和解开Foo构造函数,特别是当我尝试对其lift进行计算时,因为我无法弄清楚如何实现一个MonadTrans实例为了它。
考虑这个关于和 的玩具练习:我们需要根据一组预定义的规则过滤数据包列表。我们还需要根据另一组规则记录一些数据包。现在考虑两个增强功能:WriterWriterT
WriterT w IO)我已经实现了 1,但我坚持将其扩展为 2。首先,下面是 1 的代码。该merge函数处理当前数据包,但将潜在的日志条目传递到下一步,该步骤将决定是否打印它或合并它:
import Control.Monad
import Data.List
import Control.Monad.Writer
type Packet = Int
data Log = Log {
packet :: Packet,
acceptance :: Bool,
bulk :: Int
} deriving Show
instance Eq Log where
(==) a b = packet a == packet b
incr :: Log -> Log
incr x = x {bulk = 1 + bulk x}
shouldAccept :: …Run Code Online (Sandbox Code Playgroud) 当我们有 时,为什么不IO实例化(严格)单子,如 中所提供的?我认为我们应该是代表现实本身的神奇类型。StateRealWorldControl.Monad.STRealWorld
我的意思是,回想一下 monad 的“run”函数State:
runState :: (s -> (a, s)) -> s -> a
Run Code Online (Sandbox Code Playgroud)
将其实例化为RealWorld,我们得到:
runIO :: (RealWorld -> (a, RealWorld)) -> RealWorld -> a
Run Code Online (Sandbox Code Playgroud)
RealWorld 由于无论如何我们都无法构造 的值,因此这不应该充当像 那样的后门unsafePerformIO。
原因是因为这种解释将启用 monad 转换器IOT,定义为StateT RealWorld?
我研究了这个,试图理解几个转换器单子如何相互作用,特别是更好地理解单子lift并与单子堆叠。
对于这里找到的 RWST monad (我认为这是最好的文档),它是一个堆叠的 monad,其中 Reader、Writer、State 都是一个 Monadic 层(并且按照堆叠顺序)。或者说应该如何理解呢?当我查看定义时,runRWST :: r -> s -> m (a, s, w)我将其理解为将读取器环境作为状态环境并将任何单子包装在 的m返回值周围RWS。这也意味着这个monad中只存在两层monad。即外部 monadm和包含多个 monad 的元组。
这反过来也意味着您只能使用lift一次。将读取器或状态单子中的值提升到外部单子中。
从这个意义上说get, 和ask只是应用两个内部单子之一的两个函数。对于最后一点,我仍然不确定我是否理解为什么即使阅读了这篇 stackoverflow 帖子,您仍然需要一个reader和一个state -monad 。我猜读者只对只读有意义,但如果不希望这样,可以在两个单独的状态单子周围使用变压器单子吗?
这些评论让我有理由思考并使以下内容更加明确......以下类型定义的内部单子和外部单子是什么?它本身是RWST一个包裹着(因此是外部单子)Either String(内部单子)的单子吗?
type MyRWST a = RWST
(String -> Either String …Run Code Online (Sandbox Code Playgroud) monads haskell functional-programming state-monad monad-transformers
使用mtl,派生MonadState似乎可以使状态操作正常解除:
:set -XGeneralizedNewtypeDeriving
import Control.Applicative (Applicative)
import Control.Monad.Trans ( MonadIO, liftIO )
import Control.Monad.State (MonadState, evalStateT, modify, StateT, gets)
data State = State { int:: Int }
newtype St a = St { unSt :: StateT State IO a } deriving (Functor, Applicative, Monad, MonadIO, MonadState State)
let testLift = gets int >> return () :: St ()
Run Code Online (Sandbox Code Playgroud)
对于变形金刚,没有MonadState
:set -XGeneralizedNewtypeDeriving
import Control.Monad.Trans.State.Strict (runStateT, evalStateT, modify, StateT, gets)
import Control.Monad.IO.Class ( MonadIO, liftIO )
import Control.Applicative (Applicative)
data State = State …Run Code Online (Sandbox Code Playgroud) 我在Haskell中编写了以下代码:
import Data.IORef
import Control.Monad
import Control.Monad.Trans.Cont
import Control.Monad.IO.Class
fac n = do
i<-newIORef 1
f<-newIORef 1
replicateM_ n $ do
ri<-readIORef i
modifyIORef f (\x->x*ri)
modifyIORef i (+1)
readIORef f
Run Code Online (Sandbox Code Playgroud)
这是非常好的代码,它将factorial实现为命令式函数.但是replicateM_无法完全模拟真实for循环的使用.所以我尝试使用continuation创建一些东西,但我在这里失败的是我的代码:
ff = (`runContT` id) $ do
callCC $ \exit1 -> do
liftIO $ do
i<-newIORef 1
f<-newIORef 1
callCC $ \exit2 -> do
liftIO $ do
ri<-readIORef i
modifyIORef (\x->x*ri)
modifyIORef i (+1)
rri<-readIORef i
when (rri<=n) $ exit2(())
liftIO $ do
rf<-readIORef f
return rf
Run Code Online (Sandbox Code Playgroud)
你能帮我纠正我的代码吗?谢谢
我不是很好的哈斯克尔程序员.我的任务是在我的大学编写一个编译器,我选择了haskell,因为它是用于此目的的好工具.我使用monads StateT和ExcepT,所以我有类型:
type Runner r s = StateT s (ExceptT LatteError IO) r
type RT r s = IO (Either LatteError (r, s))
Run Code Online (Sandbox Code Playgroud)
我用它创建walk一个程序树并生成asm代码,它可以按我的意愿工作.作为在树上行走的主要功能我使用
rProgram :: Program -> Runner [String] CompileState
Run Code Online (Sandbox Code Playgroud)
并解压缩结果我使用的功能
runR program = runExceptT (runStateT (rProgram program) initialCompileState)
Run Code Online (Sandbox Code Playgroud)
我想要做的不是有一些验证器,如类型检查,身份存在检查,我知道写它们.让我告诉我
tcProgram :: Program -> Runner () TypeCheckState
ieProgram :: Program -> Runner () IdentExistanceState
Run Code Online (Sandbox Code Playgroud)
我想以优雅的方式运行它们,并且throwError指示失败.如何把像他们这样的很多功能放在一起?
我正在学习State Monad,并被告知它已不存在,第一个问题是为什么Haskell删除了它?
当我使用
import Data.Functor.Identity
import Control.Monad.Trans.State
type State s = StateT s Identity
Run Code Online (Sandbox Code Playgroud)
我懂了
Ambiguous occurrence ‘State’
It could refer to
either ‘Control.Monad.Trans.State.State’
or ‘Main.State’,
Run Code Online (Sandbox Code Playgroud)
但是当我尝试时:t State,我什么也没找到。这是自相矛盾的,我想知道它是否存在?
最后,我自己写
newtype State s a = State { runState :: s -> (a, s) }
Run Code Online (Sandbox Code Playgroud)
但是我还需要其他一些功能,例如put,get...它们在哪里。
使用:i get中,我发现MonadState,这是新的实施 State?