- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对 monad 转换器有点陌生,目前正在尝试在项目中使用 StateT/Except
堆栈。我遇到的困难是我有几层数据组合(对其进行操作的类型,包含在对其进行其他操作的类型中),并且我无法弄清楚如何在该设计中优雅地使用 monad 转换器。具体来说,我在编写以下代码时遇到了困难(显然是简化的示例):
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Monad.Except
import Control.Monad.State
import Control.Monad.Trans.Except (Except, throwE)
import Control.Monad.Trans.State (StateT)
data ComposedState = ComposedState { state :: Bool }
data MyError = MyError { message :: String }
-- If the passed in state is true, change it to false; otherwise throw.
throwingModification :: ComposedState -> Except MyError ComposedState
throwingModification (ComposedState True) = return $ ComposedState False
throwingModification _ = throwE $ MyError "error!"
-- A state which composes with @ComposedState@,
data MyState = MyState { composed :: ComposedState }
-- and a monad transformer state to allow me to modify it and propagate
-- errors.
newtype MyMonad a = MyMonad { contents :: StateT MyState (Except MyError) a }
deriving ( Functor
, Applicative
, Monad
, MonadState MyState
, MonadError MyError )
anAction :: MyMonad ()
anAction = do -- want to apply throwingModification to the `composed` member,
-- propogating any exception
undefined
我在 CompositedState
上有一个潜在的“抛出”操作,并且我想在 MyState
上的有状态抛出操作中使用该操作。显然,我可以通过解构整个堆栈并重建它来做到这一点,但单子(monad)结构的重点是我不必这样做。有没有简洁、惯用的解决方案?
对冗长的代码片段表示歉意——我已尽力将其缩短。
最佳答案
更自然的方法是在 MyMonad
monad 中从头开始编写 throwingModification
,如下所示:
throwingModification' :: MyMonad ()
throwingModification' = do ComposedState flag <- gets composed
if not flag then throwError $ MyError "error!"
else modify (\s -> s { composed = (composed s)
{ Main.state = False } })
我在这里假设组合状态包含您想要保留的其他组件,这使得 modify
子句很难看。使用镜头可以使这个更干净。
但是,如果您坚持使用当前形式的 throwingModification,您可能必须编写自己的组合器,因为通常的状态组合器不包含切换状态类型的机制s
,这就是您实际上正在尝试做的事情。
以下 usingState
定义可能会有所帮助。它使用 getter 和 setter 将 StateT 操作从一种状态转换为另一种状态。 (同样,镜头方法会更干净。)
usingState :: (Monad m) => (s -> t) -> (s -> t -> s)
-> StateT t m a -> StateT s m a
usingState getter setter mt = do
s <- get
StateT . const $ do (a, t) <- runStateT mt (getter s)
return (a, setter s t)
我认为没有一种简单的方法可以修改 usingState
以在通用 MonadState
monad 之间工作,而不是直接在 StateT
上工作,所以您需要手动提升它并通过 MyMonad
数据类型进行转换。
通过如此定义的usingState
,您可以编写以下内容。 (注意 >=>
来自 Control.Monad
。)
MyMonad $ usingState getComposed putComposed $
StateT (throwingModification >=> return . ((),))
与助手:
getComposed = composed
putComposed s c = s { composed = c }
这仍然有点难看,但那是因为类型 t -> except e t
必须适应 StateT (t -> except e ((), t))
code>,然后由组合器转换为 s
状态,然后手动包装在 MyMonad
中,如上所述。
我并不是说镜头是 Elixir 或者什么,但它们确实有助于清理代码中一些更丑陋的部分。
添加镜头后:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Monad ((>=>))
import Control.Monad.Except (Except, MonadError, throwError)
import Control.Monad.State (get, MonadState, runStateT, StateT(..))
data MyError = MyError { _message :: String }
data MyState = MyState { _composed :: ComposedState }
data ComposedState = ComposedState { _state :: Bool }
makeLenses ''ComposedState
makeLenses ''MyError
makeLenses ''MyState
throwingModification
的定义看起来更清晰一些:
throwingModification :: ComposedState -> Except MyError ComposedState
throwingModification s =
if s^.state then return $ s&state .~ False
else throwError $ MyError "error!"
以及我上面给出的 MyMonad
版本当然有好处:
throwingModification' :: MyMonad ()
throwingModification' = do
flag <- use (composed.state)
if flag then composed.state .= False
else throwError (MyError "error!")
usingStateL
的定义看起来并没有太大不同:
usingStateL :: (Monad m) => Lens' s t -> StateT t m a -> StateT s m a
usingStateL tPart mt = do
s <- get
StateT . const $ do (a, t) <- runStateT mt (s^.tPart)
return (a, s&tPart .~ t)
但它允许使用现有的镜头composed
来代替辅助函数:
MyMonad $ usingStateL composed $
StateT (throwingModification >=> return . ((),))
如果你有复杂的嵌套状态,它会泛化为(composed.underneath.state4)
。
关于haskell - 如何结合数据组合和 monad 转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46576150/
我有一个 mysql 表,其中包含一些随机数字组合。为简单起见,以下表为例: index|n1|n2|n3 1 1 2 3 2 4 10 32 3 3 10 4 4
我有以下代码: SELECT sdd.sd_doc_classification, sdd.sd_title, sdd.sd_desc, sdr.sd_upl
如果我有两个要合并的数据框 Date RollingSTD 01/06/2012 0.16 01/07/2012 0.18 01/08/2012 0.17 01/09/20
我知道可以使用 lein ring war 创建一个 war 文件,但它似乎仍然包含码头依赖项。当我构建 war (并在 tomcat 上部署)时,有没有办法排除码头依赖项? 如果我根本不能做这件事,
维基百科关于封装的文章指出: “封装还通过防止用户将组件的内部数据设置为无效或不一致的状态来保护组件的完整性” 我在一个论坛上开始讨论封装,在那里我问你是否应该始终在 setter 和/或 gette
对于我使用的组合框内的复选框: AOEDComboAssociationName = new Ext.form.ComboBox({ id: 'AOEDComboAssociationName',
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: How do I combine LINQ expressions into one? public boo
如何在 rust 中找到排列或组合的数量? 例如C(10,6) = 210 我在标准库中找不到这个函数,也找不到那里的阶乘运算符(这就足够了)。 最佳答案 以@vallentin 的回答为基础,可以进
我有一个复杂的泛型类型用例,已在下面进行了简化 trait A class AB extends A{ val v = 10 } trait X[T<:A]{ def request: T }
如何使用 Hibernate 限制来实现此目的? (((A='X') and (B in('X',Y))) or ((A='Y') and (B='Z'))) 最佳答案 思考有效 Criteria c
我一定会在我的一个项目中使用谷歌图表。我需要的是,显示一个条形图,并且在条形图中,与每个条形相交的线代表另一个值。如果您查看下面的 jsfiddle,您会发现折线图仅与中间的条形图相交,并继续向其他条
只是一个简单的问题,我也很想得到答案,因为我不能百分百理解 Javascript 示例:假设您提示用户输入名称。够简单吧?但是你有一个数组,上面写着一些名字(其中之一就是),基本上就是我到目前为止所说
我试图通过 Haskell 理解函数式编程,但在处理函数组合时遇到了很多麻烦。 其实我有这两个功能: add:: Integer -> Integer -> Integer add x y = x
我正在寻找一种在 Realm 查询中组合 AND 和 OR 的方法。 这是我的课: class Event extends RealmObject { String id; String
例如,我有一个包含 5 个元素的哈希: my_hash = {a: 'qwe', b: 'zcx', c: 'dss', d: 'ccc', e: 'www' } 我的目标是每次循环哈希时都返回,但没
我是Combine 的新手,我想得到一个看似简单的东西。假设我有一个整数集合,例如: let myCollection = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 我想以例如 0
关于“优先组合而不是继承”的问题,我的老师是这样说的: 组合:现有类成为新类的组件 转发:新类中的每个实例方法,在现有类的包含实例上调用相应的方法并返回结果 包装器:新类封装了现有的 这三个概念我不是
我正在尝试将单个整数从 ASCII 值转换为 0 和 1。相关代码如下所示: int num1 = bin.charAt(0); int num2 = bin.charAt(1);
这个问题已经有答案了: What is a NullPointerException, and how do I fix it? (12 个回答) 已关闭 7 年前。 我经常看到“嵌套”类中的非静态变
我尝试合并两个数据集(DataFrame),如下所示: D1 = pd.DataFrame({'Village':['Ampil','Ampil','Ampil','Bachey','Bachey',
我是一名优秀的程序员,十分优秀!