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包的索引位于:

  • https://hackage.haskell.org/package/d3js-0.1.0.0/docs/doc-index.html
  • 您可以通过以下方式到达:

  • 访问包装的首页
  • 在导出的模块树列表中单击任何模块名称
  • 在右上角有链接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包中获得),因此您不必使用ReaderTWriterTStateT构建自己的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。
  • 呼叫barsVar' Selection通过第一步返回。
  • Var' SelectionSelection之间有什么区别? 老实说,我不确定。

    >>>运算符

    >>>是一个箭头操作符。 箭头是将计算表达为操作流水线的一种方式。 这个页面上的例子应该让你知道它是如何使用的:

    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
    

    可以理解为:

  • 从d3对象开始。 这会返回一个选择。
  • 选择该选择的父项。
  • 调用JS函数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)一个正确的输出。

    链接地址: http://www.djcxy.com/p/43249.html

    上一篇: How do the operators `>>>` and `>>=` work in Haskell?

    下一篇: Can Haskell make distinctions for different kinds of IO