没有monad变换器的monad的明确示例是什么?

时间:2018-05-09 19:17:21

标签: haskell functional-programming monads monad-transformers

Monad变换器以所有标准monad(Reader,Writer,State,Cont,List等)而闻名,但这些monad变换器中的每一个都以稍微不同的方式工作。在给定具有monad实例的类型构造函数的定义的情况下,没有用于构造monad变换器的通用方法或公式。因此,不能保证根据某些任意业务要求设计的monad数据类型将具有monad变换器。有这样一个明确的例子吗?

相关工作

Another question解释说,两个monad的仿函数组合不一定是monad。另见this question。这些例子没有回答当前的问题 - 它们仅仅说明了没有构造单子变压器的一般方法的问题。这些例子表明,给定两个单子M和N,我们有时会发现M(N a)是单子,有时N(M a)是单子,有时也不是单子。但这既没有说明如何为M或N构造monad变换器,也没有表明它是否存在。

An answer to another question认为IO monad 不能拥有monad变换器,因为如果它有一个IOT,我们可以将IOT应用于{ {1}},然后将空列表(List)提升到生成的monad中,必须撤消IO monad“之前”执行的副作用。这个论点是基于lift [] monad“实际上执行”可能无法撤消的副作用的想法。但是,IO monad不是显式类型构造函数。

讨论

在明确给出monad类型的每个示例中,可以找到monad变换器以某种方式, - 有时需要一定的独创性。例如,Haskell库中存在的IO转换器relatively recently被发现是不正确的,但最终通过更改ListT的定义来解决问题。

没有变换器的monad的标准示例是monad,例如ListT,它实际上不是由显式类型构造函数定义的 - IO是由库以某种方式定义的不透明“魔术”类型,处于低级别。很明显,一个不能IO定义为显式类型构造函数,并且纯函数给出了monad实例。 IO示例显示,如果我们允许monad实例包含具有不纯副作用的隐藏低级代码,则monad转换器可能无法存在。所以,让我们将注意力限制在使用纯函数实现的monad上。

似乎没有一种算法能够从monad的源代码中自动导出monad变换器。我们甚至知道这总是可能的吗?

为了让我更清楚一个monad的“明确例子”我的意思:假设我声称

IO

可以有一个关于类型参数 type Q u v a = ((u -> (a, Maybe a)) -> v) -> u -> (a, Maybe a) 的合法Monad实例,并且我为a Monad实例的实现生成纯粹的源代码函数Q u vreturn。那么我们是否知道join有一个monad变换器Q u vQT u v相当于QT u v Id,monad变换器的定律是什么?那么我们是否知道如何明确地构造Q u v?我没有。

要决定这个问题,我们需要

  • 演示一种算法,该算法可以从任意给定类型构造函数和monad实例的给定实现中找到monad变换器;例如给定代码QT并为此实现monad实例,以找到monad转换器的代码;为了简单起见,我们限制自己使用type F a = r -> Either (a, a) (a, a, Maybe a),元组和->的任意组合来构造构造函数。或
  • 演示一个反例:一个显式 monad类型构造函数,由显式代码定义给出,例如: Either或其他任何内容,以便这是一个合法的type F a = r -> Either (a, a, a) (a, a, Maybe a),其中Monad实例由纯函数给出,但我们可以证明 Monad没有monad变压器。

1 个答案:

答案 0 :(得分:1)

这不是一个答案,但它对评论来说太大了。我们可以写

{-# 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)

但我们实际上可以用这个来制作monad变换器:

import Control.Monad.Trans.Free

newtype IOT m a = IOT {unIOT :: FreeT IOF m a}
  deriving (Functor, Applicative, Monad, MonadTrans)

所以我并不认为即使IO被排除在外,尽管那种情况下的同构不是"内部"。

相关问题