缺少的<<操作符

时间:2019-04-10 18:31:35

标签: haskell monads

今天,我想编译base中今天可用的不同但相关的运算符的列表,并询问为什么缺少此运算符:(<<)?我为冗长的序言道歉,但这是有关Haskell相当基本的部分的问题,我找不到答案。

编辑 @Bob Dalgleish感谢您指出这一点。似乎已经有一个这样的问题:Why is there no << in the Haskell standard library?太好了,因为这意味着我不是唯一对此感到疑惑的人。但是,对该问题的公认答案是“没有充分的理由”,恕我直言不令人满意。同样,该答案还指出可以使用<*来代替,这是不正确的,因为它们具有不同的语义。阅读下面的详细信息。

我不会详细介绍每个运算符的功能以及它的用途,但是我将列出它们的类型签名,中缀优先级以及关联性:

应用程序

功能

  • 应用程序:($) :: (a -> b) -> a -> binfixr 0
  • 已翻转的应用程序:(&) :: a -> (a -> b) -> binfixl 1

Functor

  • fmap:(<$>) :: Functor f => (a -> b) -> f a -> f binfixl 4
  • 翻转的fmap:(<&>) :: Functor f => f a -> (a -> b) -> f binfixl 1
  • 舍弃左:($>) :: Functor f => f a -> b -> f binfixl 4
  • 放弃权利:(<$) :: Functor f => a -> f b -> f ainfixl 4

重复性

  • 应用程序:(<*>) :: Applicative f => f (a -> b) -> f a -> f binfixl 4 <*>
  • 翻转的应用程序:(<**>) :: Applicative f => f a -> f (a -> b) -> f binfixl 4 <**>
  • 舍弃左:(*>) :: Applicative f => f a -> f b -> f binfixl 4 *>
  • 放弃权利:(<*) :: Applicative f => f a -> f b -> f ainfixl 4 <*

Monad

  • 绑定:(>>=) :: Monad m => m a -> (a -> m b) -> m binfixl 1 >>=
  • 翻转绑定:(=<<) :: Monad m => (a -> m b) -> m a -> m binfixr 1 =<<
  • 舍弃左:(>>) :: Monad m => m a -> m b -> m binfixl 1 >>
  • 缺少丢弃权!

我希望在这些方面有一个定义:

-- | Just like `(>>)`, but with arguments flipped.
(<<) :: Monad m => m b -> m a -> m b
k << m = const k =<< m
infixr 1 <<

这等同于(<<) = flip (>>)k << m = (\_ -> k) =<< m

有些人可能会说:“如果可以使用<<,为什么我们需要<*?”。但是这两个运算符非常不同:

  • 它们可能使用了不同的实现,毕竟>><*是具有默认实现的两个不同类的函数,可以被覆盖。
  • 由于优先级的不同,我们经常不能在没有括号的情况下将<*=<<一起使用,或者将*>>>=一起使用:
    • pure 5 >>= print >> pure 6(pure 5 >>= print) *> pure 6
  • 对于Applicative来说,信息总是从左向右流动,而对于单子而言,信息可以颠倒:
    • print 5 *> print 7 *> print 6 == print 5 <* print 7 <* print 6
    • print 5 >> print 7 >> print 6 / = print 5 << print 7 << print 6

组成:

我们对函数组成非常熟悉。它也具有从右到左流动的信息,并且不自然地从左到右流动,即看起来有点尴尬。没什么大不了的,但是我还是想提一下。

  • 撰写:(.) :: (b -> c) -> (a -> b) -> a -> cinfixr 9 .

这里有两个示例,它们按功能(不是运算符)的顺序执行

-- 4.         3.      2.            1.
λ> print 8 << print . succ =<< 6 <$ print 5
5
7
8

请注意,如果使用*>而不是>>,则需要括号,否则它将无法编译。

--  1.               3.      2.       4
λ> print 5 $> 6 >>= print . succ >> print 8
5
7
8

一致性

最后,所有运算符都有相反的方向。上面列出了其中的一些,但还有以下内容:  * Kleisli:(>=>)(<=<)  *类别:(>>>)(<<<)  *箭头:(^>>) vs (<<^)(>>^) vs (^<<)

那我们为什么没有(<<)

  • 是否有一些根本原因将其排除在外?
  • 也许没有人真正关心这种编程风格,人们倾向于只坚持使用do表示法吗?
  • 也许人们发现从右到左的流量信息令人困惑。但这会让我感到惊讶,因为功能组合就像Haskell中的面包和黄油一样。
  • 很难找到有关此主题的任何信息,部分原因是在线搜索特殊字符不容易,部分原因是有关monad的教程过多:)指向此类讨论的任何链接都将受到赞赏。

对于那些将来使用谷歌搜索的人来说,这是一个没有运算符的问题:为什么我们没有左摩纳德绑定运算符来丢弃正确动作的结果?

0 个答案:

没有答案