今天,我想编译base
中今天可用的不同但相关的运算符的列表,并询问为什么缺少此运算符:(<<)
?我为冗长的序言道歉,但这是有关Haskell相当基本的部分的问题,我找不到答案。
编辑 @Bob Dalgleish感谢您指出这一点。似乎已经有一个这样的问题:Why is there no << in the Haskell standard library?太好了,因为这意味着我不是唯一对此感到疑惑的人。但是,对该问题的公认答案是“没有充分的理由”,恕我直言不令人满意。同样,该答案还指出可以使用<*
来代替,这是不正确的,因为它们具有不同的语义。阅读下面的详细信息。
我不会详细介绍每个运算符的功能以及它的用途,但是我将列出它们的类型签名,中缀优先级以及关联性:
($) :: (a -> b) -> a -> b
(infixr 0
)(&) :: a -> (a -> b) -> b
(infixl 1
)(<$>) :: Functor f => (a -> b) -> f a -> f b
(infixl 4
)(<&>) :: Functor f => f a -> (a -> b) -> f b
(infixl 1
)($>) :: Functor f => f a -> b -> f b
(infixl 4
)(<$) :: Functor f => a -> f b -> f a
(infixl 4
)(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(infixl 4 <*>
)(<**>) :: Applicative f => f a -> f (a -> b) -> f b
(infixl 4 <**>
)(*>) :: Applicative f => f a -> f b -> f b
(infixl 4 *>
)(<*) :: Applicative f => f a -> f b -> f a
(infixl 4 <*
)(>>=) :: Monad m => m a -> (a -> m b) -> m b
(infixl 1 >>=
)(=<<) :: Monad m => (a -> m b) -> m a -> m b
(infixr 1 =<<
)(>>) :: Monad m => m a -> m b -> m b
(infixl 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 -> c
(infixr 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
表示法吗?对于那些将来使用谷歌搜索的人来说,这是一个没有运算符的问题:为什么我们没有左摩纳德绑定运算符来丢弃正确动作的结果?