Monad变压器是众所周知的所有标准单体(阅读器,作家,州,Cont,列表等),但这些单一变压器的工作方式略有不同。没有构造单台变压器的一般方法或公式,给出了带有单一实例的类型构造器的定义。因此,不能保证根据某些任意业务需求设计的单一数据类型会有一个单一数据转换器。有这样一个明显的例子吗?
相关工作
另一个问题解释说,两个单子的函子组合不一定是一个单子。另见这个问题。这些例子并没有回答这个问题--它们只是说明了没有一般的方法来构造单台变压器的问题。这些例子表明,给定两个单模M和N,我们有时会发现M (N )是单模,有时N (M )是单模,有时两者都不是单模。但这既没有说明如何构造M或N的单变压器,也没有说明它是否存在。
对另一个问题的回答认为,IO
monad不可能有一个monad转换器,因为如果它有一个IOT
,我们可以将IOT
应用于List
,然后将一个空列表(lift []
)提升到产生的monad中,就必须消除IO monad“早期”执行的副作用。这个论点是基于这样一种想法,即IO
单片“实际上执行”副作用,这大概是无法撤销的。但是,IO
monad不是显式类型构造函数。
讨论
在每一个明确给出单一类型的例子中,可以以某种方式找到单一变压器--有时需要一定的聪明才智。例如,存在于Haskell库中的ListT
转换器以一种微妙的方式被相对最近发现是不正确的,但是通过更改ListT
的定义最终解决了这个问题。
没有变压器的monads的标准示例是monads,例如IO
,它实际上不是由显式类型构造器定义的-- IO
是库以某种方式在低级定义的不透明“魔术”类型。显然,不能将IO
定义为显式类型构造函数,而使用纯函数提供的monad实例。IO
示例表明,如果我们允许monad实例包含隐藏的低级别代码,并且具有不纯的副作用,那么单方转换器可能就不存在了。因此,让我们将注意力限制在使用纯函数实现的monads上。
似乎没有一种算法可以自动从monad的源代码中派生出单台变压器。我们知道这一直都是可能的吗?
为了更清楚地说明我所说的一个单子的“明显的例子”是什么意思:假设我声称
type Q u v a = ((u -> (a, Maybe a)) -> v) -> u -> (a, Maybe a)
可以有一个关于类型参数a
的合法a
实例,并且我为Q u v
的Monad
实例的实现生成源代码,作为纯函数return
和join
。那么,我们是否知道Q u v
有一个单变压器QT u v
,使得QT u v Id
等同于Q u v
,并且单台变压器的定律仍然有效?那么,我们知道如何显式地构造QT
吗?我没有。
要决定这个问题,我们需要
type F a = r -> Either (a, a) (a, a, Maybe a)
和用于此的monad实例的实现,以查找monad转换器的代码;为了简单起见,让我们将自己限制在由->
、tuple和Either
组合组成的构造函数的类型上;或type F a = r -> Either (a, a, a) (a, a, Maybe a)
或其他什么)给出,这是一个合法的Monad
,其中一个Monad
实例由纯函数提供,但我们可以证明F
没有单一转换器。发布于 2018-05-10 18:04:44
这不是一个答案,但对评论来说太大了。我们可以写
{-# LANGUAGE GeneralizedNewtypeDeriving
, DeriveFunctor #-}
import Control.Monad.Free
-- All the IO primops you could ever need
data IOF a = PutStrLn String a
| GetLine (String -> a)
deriving Functor
newtype MyIO a = MyIO {unMyIO :: Free IOF a}
deriving (Functor, Applicative, Monad)
但是我们实际上可以用这个做一个单台变压器:
import Control.Monad.Trans.Free
newtype IOT m a = IOT {unIOT :: FreeT IOF m a}
deriving (Functor, Applicative, Monad, MonadTrans)
因此,我并不认为即使IO
也被排除在外,尽管在这种情况下的同构不是“内部”的。
https://stackoverflow.com/questions/50260591
复制相似问题