gpt4 book ai didi

haskell - 将 StateT 移入和移出 IO

转载 作者:行者123 更新时间:2023-12-03 09:57:03 26 4
gpt4 key购买 nike

我确定我一定遗漏了什么。

我是 Haskell 的新手,曲线非常陡峭。在我的玩具项目中,我真的很想使用 State monad 来避免在任何地方传递一千个参数。我无法理解如何将 State monad 从 IO 传递到纯代码中。概念上是这样的(除了 StateT 而不是 ExceptT):

import Control.Monad.Except
import Control.Monad.Identity

type PlayM = Except String
type PlayMIO = ExceptT String IO

puree :: String -> PlayM String
puree = return . ("bb"++)

impuree :: String -> PlayMIO String
impuree s = do
a <- return $ runIdentity $ runExceptT $ puree s
return $ "aa" ++ a

main = do
runExceptT $ impuree "foo"
putStrLn "hi"

除了这不编译,给我这样的东西:
play.hs:15:20:
Couldn't match expected type ‘[Char]’
with actual type ‘Either String String’
In the second argument of ‘(++)’, namely ‘a’
In the second argument of ‘($)’, namely ‘"aa" ++ a’

我现在明白为什么这不能编译以及为什么类型是它们的样子,但对于我的生活,我无法理解如何做到这一点。这感觉应该不难,但我对 Haskell 的直觉远非准确。

谢谢你的帮助!

-G

最佳答案

你很接近。让我们遵循带有类型孔的类型(_ s):

impuree :: String -> PlayMIO String
impuree s = do
a <- _ . runIdentity . runExceptT $ puree s
return $ "aa" ++ a

这告诉我们我们需要一个类型:
Test.hs:15:8:
Found hole ‘_’
with type: m0 (Either String String) -> ExceptT String IO [Char]
Where: ‘m0’ is an ambiguous type variable
Relevant bindings include
s :: String (bound at Test.hs:13:9)
impuree :: String -> PlayMIO String (bound at Test.hs:13:1)
In the first argument of ‘(.)’, namely ‘_’
In the expression: _ . return . runIdentity . runExceptT
In a stmt of a 'do' block:
a <- _ . return . runIdentity . runExceptT $ puree s

现在,我们有了可以转动 m (Either e b) 的东西。成 ExceptT e m b :
ExceptT :: m (Either e b) -> ExceptT e m b

应用它,我们得到正确的答案:
impuree :: String -> PlayMIO String
impuree s = do
a <- ExceptT . return . runIdentity . runExceptT $ puree s
return $ "aa" ++ a

如果我们查看文档,我们可以看到模式 ExceptT . f . runExceptT用函数抽象出来
mapExceptT :: (m (Either e a) -> n (Either e' b)) -> ExceptT e m a -> ExceptT e' n b

在我们的例子中, mIdentitynIO .使用这个,我们得到:
impuree :: String -> PlayMIO String
impuree s = do
a <- mapExceptT (return . runIdentity) $ puree s
return $ "aa" ++ a

抽象模式

这在这里可能有点矫枉过正,但值得注意的是有一个名为 mmorph 的包。这使得与 monad 态射(从一个 monad 到另一个 monad 的转换)一起工作变得更好。这个包有一个功能 generalize :: Monad m => Identity a -> m a 我们可以使用:
impuree :: String -> PlayMIO String
impuree s = do
a <- mapExceptT generalize $ puree s
return $ "aa" ++ a

进一步概括

当我们谈论 mmorph ,我们不妨使用更一般的形式:
impuree :: String -> PlayMIO String
impuree s = do
a <- hoist generalize $ puree s
return $ "aa" ++ a

hoist 概括 mapExceptT对于任何类似 monad 转换器的东西,您可以将 monad 态射应用于底层 monad:
hoist :: (MFunctor t, Monad m) => (forall a. m a -> n a) -> t m b -> t n b

这里第一个正确答案之后的所有内容都只是额外的东西,没有必要为了理解和使用解决方案而理解它。不过,它在某些时候可能会派上用场,这就是我将其包含在内的原因。认识 monad 态射的一般模式可以节省时间,但您总是可以更明确地做事情,而无需额外的抽象级别。

关于haskell - 将 StateT 移入和移出 IO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32106814/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com