Haskell中运算符`>>>`和`>> =`如何工作?
我一直在阅读一个Haskell d3js库:
这是定义Haskell框的代码:
box :: Selector -> (Double,Double) -> St (Var' Selection)
box parent (w,h) = do
assign
$ ((d3Root
>>> select parent
>>> func "append" [PText "svg"]
>>> width w
>>> height h
>>> style "background" "#eef") :: Chain () Selection)
使用d3.js代码中的box函数实际导出的代码使用>>=运算符,如下所示:
import Control.Monad
import qualified Data.Text as T
import D3JS
test :: Int -> IO ()
test n = T.writeFile "generated.js" $ reify (box "#div1" (300,300) >>= bars n 300 (Data1D [100,20,80,60,120]))
为避免出现像箭头这样不受欢迎的问题:如何在haskell中使用箭头运算符在哪里可以找到类型签名或其他基本信息? 是否有资源可以进一步了解:
$ Haskell:之间的区别。 (点)和$(美元符号) >>>这可能是一个箭头,但我不知道我在哪里导入它。 >>= 第一个很容易找到,但答案令人困惑:
*Main Lib> :t ($)
($) :: (a -> b) -> a -> b
我发现f $ abc = f ( (ab) c )而fabc = (((fa) b) c
Prelude对>>=涉及monad给出了类似的回应。 就我而言,它可能是IO monad。 或者d3js声明monad St()
*Main Lib> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
最后一个根本没有出现......这太糟糕了,因为它看起来非常重要
*Main Lib> :t (>>>)
<interactive>:1:1:
Not in scope: ‘>>>’
Perhaps you meant one of these:
‘>>’ (imported from Prelude), ‘>>=’ (imported from Prelude)
最后一次冒着捆绑太多问题的风险。 有人可以解释这种类型的签名? 特别是最后一个项目:
box :: Selector -> (Double,Double) -> St (Var' Selection)
包索引
Hackage上的软件包通常具有定义的所有功能/类型/等的索引页面。 d3js包的索引位于:
您可以通过以下方式到达:
Source | Contents | Index | Style Source | Contents | Index | Style Source | Contents | Index | Style 。 点击索引链接。 什么是St ?
St被定义为
type St r = RWS () Text Int r
RWS只是一个具有读写器,写入器和状态功能的monad。 Reader环境是() ,它写入Text值和一个Int状态。
这是一个方便的定义(可从mtl包中获得),因此您不必使用ReaderT , WriterT和StateT构建自己的monad变压器堆栈。
请注意,阅读器环境是() ,这意味着库只是真正使用monad的作者和状态方面。
box ... >= box ...如何box ... >= box ...工作?
该box功能有类型:
box :: Selector -> (Double, Double) -> St (Var' Selection)
这意味着它需要一个Select和一对双打,并在St单元中返回一个Var' Selector 。
表达式box "#div1" (300,300) >>= bars n 300 (Data1D [...])与以下内容相同:
do vs <- box "#div1" (300,300)
bars n 300 (Data1D [...]) vs
解释:
box函数以创建Var' Selection 。 这发生在St monad。 bars与Var' Selection通过第一步返回。 Var' Selection和Selection之间有什么区别? 老实说,我不确定。
>>>运算符
>>>是一个箭头操作符。 箭头是将计算表达为操作流水线的一种方式。 这个页面上的例子应该让你知道它是如何使用的:
https://www.haskell.org/arrows/syntax.html
请注意, >>>是根据类型类定义的,所以它的确切作用取决于您使用的类型。 在这种情况下,它与Chain () Selection值一起使用。
如果你读的文档Chain (链接),你会看到评论:
链ab的行为就像(a - > b)。 Val Var是链条的起点(=常数),Nil是链条的终止点。
所以这个片段:
-- type:
d3Root >>> select parent -- Chain () Selection
>>> func "append" [PText "svg"] -- Chain a b
>>> width w -- Chain a a
>>> height h -- Chain a a
>>> style ... -- Chain a a
可以理解为:
append参数"svg" 有趣的是, func函数的类型是Chain ab - 它具有不受限制的返回类型b 。 这就是为什么我怀疑最后有明确的类型签名,例如:: Chain () Selection 。
因为@delta已经说过hoogle是你的朋友 - 这里输入的片段来自Control.Category - 它表示态射的从左到右的组合。
在这种情况下,手头的类别是与monad相关的Kleisli类别,它仅仅是Hask的一个子类别 - 那么>>>运算符就是缺少的链接,可以使函数
f :: m a -> m b
g :: m b -> m c
彼此适当地工作。 而
>>= :: m a -> (a -> m b) -> m b
将无法做到这一点,专业版的(>>>)
>>> :: (m a -> m b) -> (m b -> m c) -> ma -> m c
会给你h = (f >>> g)一个正确的输出。
上一篇: How do the operators `>>>` and `>>=` work in Haskell?
下一篇: Can Haskell make distinctions for different kinds of IO
