haskell中的单子变压器是独特的吗?

发布于 2025-02-04 07:49:54 字数 500 浏览 2 评论 0原文

有几个问题(例如io“> this 和 this )询问Haskell(IO除外)中的每个单子是否都有相应的单子变压器。现在我想问一个补充问题。每个单子都完全有一个变压器(或在IO中没有一个变压器),还是可以有一个以上的变压器?

反例将是两个单子变压器,当应用于Monad的身份时,将产生相同行为的单调,但是当应用于其他单调时会产生不同的行为单调。如果答案是单子可以拥有多个变压器,我想拥有一个尽可能简单的haskell示例。这些实际上不必是有用的变压器(尽管这很有趣)。

链接的问题中的一些答案似乎表明单子可能有多个变压器。但是,除了类别的基本定义之外,我不知道太多的类别理论,因此我不确定它们是否是这个问题的答案。

There have been a couple of questions (e.g. this and this) asking whether every monad in Haskell (other than IO) has a corresponding monad transformer. Now I would like to ask a complementary question. Does every monad have exactly one transformer (or none as in the case of IO) or can it have more than one transformer?

A counterexample would be two monad transformers that would produce monads behaving identically when applied to the identity monad would but would produce differently behaving monads when applied to some other monad. If the answer is that a monad can have more than one transformer I would like to have a Haskell example which is as simple as possible. These don't have to be actually useful transformers (though that would be interesting).

Some of the answers in the linked question seemed to suggest that a monad could have more than one transformer. However, I don't know much category theory beyond the basic definition of a category so I wasn't sure whether they are an answer to this question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

趴在窗边数星星i 2025-02-11 07:49:57

这是一个反例的想法。我们知道,通常,Monad不会构成...但是我们也知道,如果有适当的交换>交换操作,您可以撰写它们[1]!让我们为可以与自己交换的单子上课。

-- | laws (from [1]):
-- swap . fmap (fmap f) = fmap (fmap f) . swap
-- swap . pure = fmap pure
-- swap . fmap pure = pure
-- fmap join . swap . fmap (join . fmap swap) = join . fmap swap . fmap join . swap
class Monad m => Swap m where
    swap :: m (m a) -> m (m a)

instance Swap Identity where swap = id
instance Swap Maybe where
    swap Nothing = Just Nothing
    swap (Just Nothing) = Nothing
    swap (Just (Just x)) = Just (Just x)

然后,我们可以构建一个与自身组成单元的单子变压器,这样:

newtype Twice m a = Twice (m (m a))

希望应该很明显pure and (< $>) do。我不会定义(>> =),我将定义JOIN,因为我认为这有点明显。 (>> =)可以从中得出。

instance Swap m => Monad (Twice m) where
    join = id
        . Twice                        -- rewrap newtype
        . fmap join . join . fmap swap -- from [1]
        . runTwice . fmap runTwice     -- unwrap newtype

instance MonadTrans Twice where lift = Twice . pure

我尚未检查lift遵守monadtrans所有swap> swap实例的法律,但是我确实检查了它们是否Identity也许

现在,我们已经

IdentityT Identity ~= Identity ~= Twice Identity
IdentityT Maybe    ~= Maybe   !~= Twice Maybe

表明Identityt不是生产Identity的唯一单调变压器。

[1]由马克·琼斯(Mark P.

Here's one idea for a counterexample to uniqueness. We know that in general, monads don't compose... but we also know that if there's an appropriate swap operation, you can compose them[1]! Let's make a class for monads that can swap with themselves.

-- | laws (from [1]):
-- swap . fmap (fmap f) = fmap (fmap f) . swap
-- swap . pure = fmap pure
-- swap . fmap pure = pure
-- fmap join . swap . fmap (join . fmap swap) = join . fmap swap . fmap join . swap
class Monad m => Swap m where
    swap :: m (m a) -> m (m a)

instance Swap Identity where swap = id
instance Swap Maybe where
    swap Nothing = Just Nothing
    swap (Just Nothing) = Nothing
    swap (Just (Just x)) = Just (Just x)

Then we can build a monad transformer that composes a monad with itself, like so:

newtype Twice m a = Twice (m (m a))

Hopefully it should be obvious what pure and (<$>) do. Rather than defining (>>=), I'll define join, as I think it's a bit more obvious what's going on; (>>=) can be derived from it.

instance Swap m => Monad (Twice m) where
    join = id
        . Twice                        -- rewrap newtype
        . fmap join . join . fmap swap -- from [1]
        . runTwice . fmap runTwice     -- unwrap newtype

instance MonadTrans Twice where lift = Twice . pure

I haven't checked that lift obeys the MonadTrans laws for all Swap instances, but I did check them for Identity and Maybe.

Now, we have

IdentityT Identity ~= Identity ~= Twice Identity
IdentityT Maybe    ~= Maybe   !~= Twice Maybe

which shows that IdentityT is not a unique monad transformer for producing Identity.

[1] Composing monads by Mark P. Jones and Luc Duponcheel

聆听风音 2025-02-11 07:49:57

身份单元至少具有两个单元变压器:身份单元变压器和 codsente monad变压器

newtype IdentityT m a = IdentityT (m a)
newtype Codensity m a = Codensity (forall r. (a -> m r) -> m r)

实际上,考虑codsential Identityforall r。 (a - &gt; r) - &gt; ra的同构。

这些单子变压器完全不同。一个示例是,“括号”可以定义为codsenty的单声道操作:

bracket :: Monad m => m () -> m () -> Codensity m ()
bracket before after = Codensity (\k -> before *> k () *> after)

而将该签名转换为Identityt并没有说明

bracket :: Monad m => m () -> m () -> IdentityT m ()  -- cannot implement the same functionality

其他示例,从而可以从尽管我还没有看到一般方案,但延续/codsenty monad的变体。

状态单元对应于状态单元变压器,以及codsentereadert的组成:

newtype StateT s m a = StateT (s -> m (s, a))
newtype CStateT s m a = CStateT (Codensity (ReaderT s m) a)

列表monad至少对应三个单核变压器,而不是包括错误的一个

newtype ListT m a = ListT (m (Maybe (a, ListT m a)))  -- list-t
newtype LogicT m a = LogicT (forall r. (a -> m r -> m r) -> m r -> m r)  -- logict
newtype MContT m a = MContT (forall r. Monoid r => (a -> m r) -> m r))

:可以在包装中分别找到前两个(也以管道),
and

The identity monad has at least two monad transformers: the identity monad transformer and the codensity monad transformer.

newtype IdentityT m a = IdentityT (m a)
newtype Codensity m a = Codensity (forall r. (a -> m r) -> m r)

Indeed, considering Codensity Identity, forall r. (a -> r) -> r is isomorphic to a.

These monad transformers are quite different. One example is that "bracket" can be defined as a monadic action in Codensity:

bracket :: Monad m => m () -> m () -> Codensity m ()
bracket before after = Codensity (\k -> before *> k () *> after)

whereas transposing that signature to IdentityT doesn't make much sense

bracket :: Monad m => m () -> m () -> IdentityT m ()  -- cannot implement the same functionality

Other examples can be found similarly from variants of the continuation/codensity monad, though I don't see a general scheme yet.

The state monad corresponds to the state monad transformer and to the composition of Codensity and ReaderT:

newtype StateT s m a = StateT (s -> m (s, a))
newtype CStateT s m a = CStateT (Codensity (ReaderT s m) a)

The list monad corresponds to at least three monad transformers, not including the wrong one:

newtype ListT m a = ListT (m (Maybe (a, ListT m a)))  -- list-t
newtype LogicT m a = LogicT (forall r. (a -> m r -> m r) -> m r -> m r)  -- logict
newtype MContT m a = MContT (forall r. Monoid r => (a -> m r) -> m r))

The first two can be found respectively in the packages list-t (also in an equivalent form in pipes),
and logict.

风苍溪 2025-02-11 07:49:57

一个单子有两个不等变压器的单个例子:“选择”单元。

 type Sel r a = (a -> r) -> a

单子不是众所周知,但有些论文提到了。这是一个涉及一些论文的软件包:

https://hackage.haskell.org/package/transformers-0.6.0.4/docs/control-monad-monad-trans-select.html

该软件包实现了一个变压器:

type SelT r m a = (a -> m r) -> m a

但是存在第二个变形金刚:证明法律:

type Sel2T r m a = (m a -> r ) -> m a

证明法律法律 :因为这个变压器更加困难,但我做到了。

第二个变压器的一个优点是它在m中是协变量的,因此可以定义HOIST函数:

 hoist :: (m a -> n a) -> Sel2T r m a -> Sel2T r n a

第二个变压器是“完全特色”,具有所有提升和“提升”。第一个变压器尚未完全出现。例如,您无法定义blift :: Sel ra-&gt; SELT RM A。换句话说,您不能将sel的单声道计算嵌入selt中,就像您无法使用Continuation Monad和Codmenta Monad这样做。

但是,使用SEL2T变压器,所有升力都存在,您可以将sel计算嵌入到sel2t中。

此示例显示了一个带有两个变压器的单子,而无需以任何方式使用码头密度构造。

There is another example of a monad that has two inequivalent transformers: the "selection" monad.

 type Sel r a = (a -> r) -> a

The monad is not well known but there are papers that mention it. Here is a package that refers to some papers:

https://hackage.haskell.org/package/transformers-0.6.0.4/docs/Control-Monad-Trans-Select.html

That package implements one transformer:

type SelT r m a = (a -> m r) -> m a

But there exists a second transformer:

type Sel2T r m a = (m a -> r ) -> m a

Proving laws for this transformer is more difficult but I have done it.

An advantage of the second transformer is that it is covariant in m, so the hoist function can be defined:

 hoist :: (m a -> n a) -> Sel2T r m a -> Sel2T r n a

The second transformer is "fully featured", has all lifts and "hoist". The first transformer is not fully featured; for example, you cannot define blift :: Sel r a -> SelT r m a. In other words, you cannot embed monadic computations from Sel into SelT, just like you can't do that with the Continuation monad and the Codensity monad.

But with the Sel2T transformer, all lifts exist and you can embed Sel computations into Sel2T.

This example shows a monad with two transformers without using the Codensity construction in any way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文