我一直关注并扩展教程自己写一个方案.我有一个LispVal包含在几层monad变换器中的类型:
import qualified Data.Map as M
data LispVal = ...
data LispError = ...
type Bindings = M.Map String (IORef LispVal)
data Env = Environment { parent :: Env, bindings :: IORef Bindings }
type IOThrowsError = ErrorT LispError IO
type EvalM = ReaderT Env IOThrowsError
Run Code Online (Sandbox Code Playgroud)
使用的想法ReaderT是,我将能够通过评估器自动传递环境(维护变量绑定),并且在使用它的地方很明显,因为会有一个调用ask.这似乎比将环境明确地作为额外参数传递更好.当我来实现continuation时,我想用ContTmonad变换器做一个类似的技巧,并避免为继续传递额外的参数.
但是,我还没有弄清楚如何通过这样做来修改环境.例如,定义新变量或设置旧变量的值.
举一个具体的例子,假设每当我评估一个if语句时,我想将变量绑定it到test子句的结果.我的第一个想法是直接修改环境:
evalIf :: [LispVal] -> EvalM LispVal
evalIf [test, consequent, alternate] = do
result <- eval test
bind …Run Code Online (Sandbox Code Playgroud) 我有一些用Lift编写的代码.基本上它的嵌套Box(类似monad to Option).如果可能的话,我想稍微简化一下.最好添加类型参数,这样可以根据需要轻松更改为字符串或双精度.这是代码
tryo(r.param("boolean parameter").map(_.toBoolean)).map(_.openOr(false)).openOr(false)
Run Code Online (Sandbox Code Playgroud)
"tryo"是辅助函数,用于捕获并在Box中包含结果,如果发生异常且r是Req对象."param"函数返回Box [String](来自请求参数).我想让它适用于Int的String等等,如果可能的话,摆脱嵌套的map/openOr(你认为在Option类型中有getOrElse).
Monad变形金刚?
我和Monad,ReaderT混淆了......要表现"简单吗?" 行为.
我想将测试函数散布到Maybe转换(Maybe或另一个个性化的monad)中.
确切地说,我想要避免t调用,创建某种monad(monad,我认为)
doCalculus :: (Int -> Bool) -> Int -> Maybe Int
doCalculus f a = do
b <- t $ a + 1
c <- t $ 2 * b
d <- t $ a + b + c
return d
where t = if f n then Just n else Nothing
Run Code Online (Sandbox Code Playgroud)
例
test :: Int -> Bool
test n = not (n `elem` [3, 7, 9])
*Main> doCalculus test 2 …Run Code Online (Sandbox Code Playgroud) 我知道数据构造函数和run***函数,
我可以将任何函数提升到特定的MonadTrans实例.
像这样,
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad
liftF :: (Monad m) => (a -> b) -> MaybeT m a -> MaybeT m b
liftF f x = MaybeT $ do
inner <- runMaybeT x
return $ liftM f inner
Run Code Online (Sandbox Code Playgroud)
但是我怎样才能将这个liftF推广到
liftF :: (MonadTrans t, Monad m) => (a -> b) -> t m a -> t m b
Run Code Online (Sandbox Code Playgroud) 假设我有函数组成两个monad动作:
co :: Monad m => m a -> m a -> m a
您可以将其co视为更高阶函数,描述两个monadic动作如何相互合作以完成任务.
但现在我发现第一个monadic动作可能包含在monad变换器中,而第二个不是:
one :: (MonadTrans t, Monad m) => t m a
two :: Monad m => m a
但是还是想把它们组合在一起,所以我需要一个功能:
co' :: (MonadTrans t, Monad m) => t m a -> m a -> t m a
因此,第一个t m a可以m a通过将所有m原语提升到上下文中来合作t.
这里的诀窍是在co不知道mor 的实现的情况下构建t.我觉得答案是在MFunctor包中的某个地方,事实上昨天也提出了类似的问题.但是想不出什么好的,有什么想法吗?
作为一个新手,很难将好的问题标题表述出来.请使这个问题搜索友好=)
试图编写我的第一个"真正的"Haskell程序(即不仅是Project Euler的东西),我试图用很好的错误消息来读取和解析我的配置文件.到目前为止,我有这个:
import Prelude hiding (readFile)
import System.FilePath (FilePath)
import System.Directory (doesFileExist)
import Data.Aeson
import Control.Monad.Except
import Data.ByteString.Lazy (ByteString, readFile)
-- Type definitions without real educational value here
loadConfiguration :: FilePath -> ExceptT String IO Configuration
loadConfiguration path = do
fileContent <- readConfigurationFile "C:\\Temp\\config.json"
configuration <- parseConfiguration fileContent
return configuration
readConfigurationFile :: FilePath -> ExceptT String IO ByteString
readConfigurationFile path = do
fileExists <- liftIO $ doesFileExist path
if fileExists then do
fileContent <- liftIO $ readFile path
return …Run Code Online (Sandbox Code Playgroud) 今天在Coding Dojo工作,我尝试了以下方法
example :: IO ()
example = do input <- getLine
parsed <- parseOnly parser input
...
Run Code Online (Sandbox Code Playgroud)
其中,parseOnly :: Parser a -> Either String a(从attoparsec课程)编译器抱怨说,Either ..没有IO ..实质上是告诉我,我混的单子.
当然这可以通过解决
case parseOnly parser input of .. -> ..
Run Code Online (Sandbox Code Playgroud)
我想,这有点不雅观.另外我的猜测是其他人之前遇到过这个问题而且我认为解决方案与monad变换器有关,但最后一点我不能拼凑在一起.
它也让我想起了liftIO- 但这是另一种方式,我认为这解决了在一些周围的monad中发生IO动作的问题(更确切地说MonadIO- 例如在内部,Snap当一个人想要stdout在获取一些http 时打印一些东西).
更一般的这个问题似乎是针对a Monad m1和a(不同)Monad m2我该怎样做的事情
example = do a <- m1Action
b <- m2Action
..
Run Code Online (Sandbox Code Playgroud) 我刚刚发现,RWST(从transformers)不携带一个实例MonadReader,MonadState或MonadWriter.这对我来说似乎有些奇怪,因为这些实例会立即提高可用性,例如能够使用.=,或者只是普遍提高可重用性.
当然这个决定有理由吗?
如何创建使用State,Cont和Reader变换器的monad?我想阅读一个环境,并更新/使用状态.但是,我还想暂停/中断动作.例如,如果满足条件,则状态保持不变.
到目前为止,我有一个使用ReaderT和StateT的monad,但我无法弄清楚如何包含ContT:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Test where
-- monads
import Data.Functor.Identity (Identity, runIdentity)
import Control.Monad.State
import Control.Monad.Reader
import Control.Monad.Cont
-- reader environment
type In = Integer
-- cont: if true then pause, else continue
type Pause = Bool
-- state environment:
newtype StateType = StateType { s :: Integer }
newtype M r = M {_unM :: ReaderT In (ContT Pause (StateT StateType Identity)) r}
deriving ( Functor, Applicative, Monad
, MonadReader In
, MonadCont Pause
, MonadState …Run Code Online (Sandbox Code Playgroud) 我有以下新类型声明。它包装了Monad堆栈变压器,堆叠了一些标准的mtl monad,例如Reader和Except。
newtype TrxDbFileBased f a = TrxDbFileBased {
unTrxDbFileBased :: ExceptT TrxDbError (ReaderT TrxDbFileBasedEnv f) a
} deriving (
Functor
, Applicative
, Monad
, MonadError TrxDbError
, MonadReader TrxDbFileBasedEnv
, MonadIO
, MonadTrans
)
data TrxDbFileBasedEnv = TrxDbFileBasedEnv {
workingDirectory :: FilePath
} deriving (Show)
data TrxDbError = TrxDbErrorIO TrxDbFileBasedEnv IOException
| TrxDbErrorStr TrxDbFileBasedEnv String
deriving (Show)
Run Code Online (Sandbox Code Playgroud)
我希望此新类型是的实例,MonadTrans但出现以下错误。
• Can't make a derived instance of ‘MonadTrans TrxDbFileBased’
(even with cunning GeneralizedNewtypeDeriving):
cannot eta-reduce the representation type …Run Code Online (Sandbox Code Playgroud)