Haskell——理解 writer 类型声明

发布于 2025-01-14 00:07:08 字数 1409 浏览 4 评论 0原文

我正在《Learn You a Haskell for Great Good!》一书中学习 monad。作者:米兰·利波瓦卡。我正在阅读有关 Control.Monad.Writer 模块如何导出 Writer wa 类型及其 Monad 实例以及一些用于处理此类型值的有用函数的信息。

它给出了一个 Writer type 声明示例。

对于以下代码:

-- Writer w a corresponding to (a, w)  <--- the order is reversed
newtype Writer w a = Writer { runWriter :: (a, w) } -- <--- (a, w)

这里,为什么pair类型顺序颠倒了?

我可以像这样声明Writer类型吗?

-- Writer w a corresponding to (w, a) <--- same order with Writer w a
newtype Writer w a = Writer { runWriter :: (w, a) } -- <--- (w, a)

如果我选择第二种Writer type声明,对编写Haskell有什么不好的影响吗?

为了找出Writer Monad,我尝试阅读Haskell Writer Monad Source Code (来自 https ://hackage.haskell.org/package/transformers-0.6.0.4/docs/src/Control.Monad.Trans.Writer.Strict.html#WriterT)

newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }

pair类型顺序也被颠倒了。为什么不能这样定义呢?

newtype WriterT w m a = WriterT { runWriterT :: m (w, a) }

这有什么原因吗?

感谢您的帮助。

I am learning about monads in the book 'Learn You a Haskell for Great Good!' by Miran Lipovaca. I am reading about how the Control.Monad.Writer module exports the Writer w a type along with its Monad instance and some useful functions for dealing with values of this type.

It gives a Writer type declaration example.

For the following code:

-- Writer w a corresponding to (a, w)  <--- the order is reversed
newtype Writer w a = Writer { runWriter :: (a, w) } -- <--- (a, w)

Here, why is the pair type order reversed?

Can I make the declaration of Writer type like this?

-- Writer w a corresponding to (w, a) <--- same order with Writer w a
newtype Writer w a = Writer { runWriter :: (w, a) } -- <--- (w, a)

If I took the second choice of Writer type declaration, Is there anything bad influence in writing Haskell?

In order to find out Writer Monad, I have tried reading Haskell Writer Monad Source Code
(From https://hackage.haskell.org/package/transformers-0.6.0.4/docs/src/Control.Monad.Trans.Writer.Strict.html#WriterT)

newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }

The pair type order is also reversed. Why can't define it like this?

newtype WriterT w m a = WriterT { runWriterT :: m (w, a) }

Is there any reason for this?

Thanks for your help.

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

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

发布评论

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

评论(1

时间你老了 2025-01-21 00:07:08

正如 swap 函数所证明的那样,一个元组(a, b)(b, a) 同构,所以是的,您可以轻松更改元组元素的顺序。能力上没有什么区别。

某些 API 的外观通常有历史原因。我不知道 Writer monad 背后的确切历史,但一般来说,如果您想象自己来自命令式/过程/面向对象的背景,则相当于基于 Writer 的 API 将是一个过程返回一个值,但也会更改一些可变状态(全局变量或可变输入参数)。

例如,在 C# 中,它可能如下所示:

public int Foo(ICollection<string> log)

其中返回值是 int,而可写资源是字符串集合。

一旦你决定摆脱突变,你必须返回一个新版本的 log,但由于该方法已经返回一个 int,你必须返回一个元组。您应该将“原始”返回类型设置为元组中的第一个元素还是第二个元素?

将“原始”返回类型作为第一个元素似乎很直观。因此,在上面的示例中,您可能会使用这样的 API(现在采用 Haskell 语法):

foo :: [String] -> (Int, [String])

或者更一般地说,

(a, w)

当涉及具有 FunctorMonad 然而,Haskell 要求在 fmap>>= 等中“参与”的类型变量是最右边的类型变量。

这就是 WriterT wm a 定义为最右边的 a 的原因,而不是 WriterT wa m作家T aw m

鉴于 a 必须位于最右侧,后续问题可能是:为什么是 WriterT wm a 而不是 WriterT mw a

这是因为通过将 'monad' 类型变量 m 放在 Writer 类型变量 w 的右侧,您可以部分应用 <代码>身份单子到WriterT 定义 Writer

type Writer w = WriterT w Identity

看看是否可以将 (a, w)(w, a) 并查看是否仍然可以实现所有实例。

As evidenced by the swap function, a tuple (a, b) is isomorphic to (b, a), so yes, you can trivially change the order of the elements of the tuple. It makes no difference in capability.

There are often historical reasons why certain APIs look as they do. I'm not aware of the exact history behind the Writer monad, but in general, if you imagine that you're coming from an imperative/procedural/object-oriented background, an API equivalent to something Writer-based would be a procedure that returns a value but also changes some mutable state (a global variable, or a mutable input argument).

In C#, for example, it might look like this:

public int Foo(ICollection<string> log)

where the return value is an int, while the writable resource is a collection of strings.

Once you decide to get rid of mutation, you have to instead return a new version of the log, but since the method already returns an int, you'll have to return a tuple. Should you make the 'original' return type the first or the second element in the tuple?

It seems intuitive to make the 'original' return type the first element. Thus, in the above example, you may instead have an API like this (now in Haskell syntax):

foo :: [String] -> (Int, [String])

or, more generally,

(a, w)

When it comes to types that have Functor and Monad instances, however, Haskell requires that the type variable that is 'engaged' in fmap, >>=, etcetera is the rightmost type variable.

That's the reason that WriterT w m a is defined with the a farthest to the right, instead of, say, WriterT w a m or WriterT a w m.

Given that the a must be farthest to the right, a follow-up question might be: Why is it WriterT w m a instead of WriterT m w a?

That's because by putting the 'monad' type variable m to the right of the Writer type variable w, you can partially apply the Identity monad to WriterT to define Writer:

type Writer w = WriterT w Identity

It may be a good exercise to see if you can swap (a, w) with (w, a) and see if you can still implement all the instances.

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