Haskell——理解 writer 类型声明
我正在《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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如 swap 函数所证明的那样,一个元组
(a, b)
与(b, a)
同构,所以是的,您可以轻松更改元组元素的顺序。能力上没有什么区别。某些 API 的外观通常有历史原因。我不知道 Writer monad 背后的确切历史,但一般来说,如果您想象自己来自命令式/过程/面向对象的背景,则相当于基于 Writer 的 API 将是一个过程返回一个值,但也会更改一些可变状态(全局变量或可变输入参数)。
例如,在 C# 中,它可能如下所示:
其中返回值是 int,而可写资源是字符串集合。
一旦你决定摆脱突变,你必须返回一个新版本的
log
,但由于该方法已经返回一个int
,你必须返回一个元组。您应该将“原始”返回类型设置为元组中的第一个元素还是第二个元素?将“原始”返回类型作为第一个元素似乎很直观。因此,在上面的示例中,您可能会使用这样的 API(现在采用 Haskell 语法):
或者更一般地说,
当涉及具有
Functor
和Monad
然而,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
:看看是否可以将
(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:
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 anint
, 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):
or, more generally,
When it comes to types that have
Functor
andMonad
instances, however, Haskell requires that the type variable that is 'engaged' infmap
,>>=
, etcetera is the rightmost type variable.That's the reason that
WriterT w m a
is defined with thea
farthest to the right, instead of, say,WriterT w a m
orWriterT a w m
.Given that the
a
must be farthest to the right, a follow-up question might be: Why is itWriterT w m a
instead ofWriterT m w a
?That's because by putting the 'monad' type variable
m
to the right of the Writer type variablew
, you can partially apply theIdentity
monad toWriterT
to defineWriter
: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.