探索这个材料:Lens over tea我遇到了一个有趣的(一开始很简单)点:
ex3 :: (a, b) -> (b, a)
ex3 = do
a <- fst
b <- snd
return (b, a)一切都很好,但是这个函数使用的是哪种类型的monad (因为我们内部有一个do-block )。经过几次尝试,我得出了这样的结论:
ex2 :: ReaderT (a, b) ((,) b) a
ex2 = ReaderT $ do
a <- fst
b <- snd
return (b, a)
ex3 :: (a, b) -> (b, a)
ex3 = runReaderT ex2因此,我们有使用内部一元((,) b)的ReaderT。有趣的是,我对此还不够满意,于是决定重写ex2,而不是使用do表示法。这是我得到的:
ex2 :: Monoid b => ReaderT (a, b) ((,) b) a
ex2 = ReaderT $
\pair -> return (fst pair) >>=
\a -> return (snd pair) >>=
\b -> (b, a) 或者甚至是:
ex2 :: Monoid b => ReaderT (a, b) ((,) b) a
ex2 = ReaderT $
\pair -> (mempty, fst pair) >>=
\a -> (mempty, snd pair) >>=
\b -> (b, a) 这两种变体都要求b具有Monoid类型限制。问题是:我能不能只用(>>=)编写这个函数,而不使用Monoid限制-就像我们用do-notation变体一样?显然,无论是否使用do-notation,我们都会做同样的事情。也许最大的区别是,我们必须在第二个和第二个函数中的每一步构造单子,这就要求我们声明"b“应该是么半群--一些么半群。在第一种情况下,我们只是从一些monad中提取我们的值-而不是构建它们。有没有人能解释一下,我的想法是正确的吗?
谢谢你!!
发布于 2018-08-23 00:50:21
您还没有完全从do表示法到(>>=)调用中去掉这一点。直接转换如下所示:
ex2 :: ReaderT (a, b) ((,) b) a
ex2 = ReaderT $
fst >>= (\a -> -- a <- fst
snd >>= (\b -> -- b <- snd
return (b, a))) -- return (b, a)此外,您实际上并没有使用(,) b的单一性,即使它适合在这里用于ReaderT的“内部单元格”。
发布于 2018-08-23 00:39:07
ex3 :: (a, b) -> (b, a)在前缀表示法中表示
ex3 :: (->) (a, b) (b, a)
-----------m
------t因此,monad是m = (->) (a, b),它是Reader (直到同构),并使用一对作为其隐式参数/只读状态。
你不需要么半群。简单的阅读器monad就足够了。如果您想使用ReaderT,请使用identity monad作为内部monad。
ex2 :: Monoid b => ReaderT (a, b) Identity (b, a)
ex2 = ReaderT $
\pair -> Identity (fst pair) >>=
\a -> Identity (snd pair) >>=
\b -> Identity (b, a) 当然,上面的代码可以简化。
发布于 2018-08-23 03:18:37
所以总结一下:
ex3‘::(a,b) -> (b,a) ex3’= fst >>= \a ->和>>= \b -> return (b,a)
https://stackoverflow.com/questions/51971403
复制相似问题