运算符`>>>`和`>> =`如何在Haskell中工作?

时间:2016-05-19 16:08:39

标签: haskell monads category-theory

我一直在阅读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]))

为了避免像箭头这个不受欢迎的问题:How to use arrow operators in haskell 我在哪里可以找到类型签名或其他基本信息? 是否有资源我可以了解更多:

第一个很容易找到,但答案令人困惑:

*Main Lib> :t ($)
($) :: (a -> b) -> a -> b

我发现f $ a b c = f ( (a b) c )f a b c = (((f a) 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)

2 个答案:

答案 0 :(得分:3)

包索引

Hackage上的软件包通常有一个定义了所有函数/类型/等的索引页。 d3js包的索引位于:

你可以通过以下方式到达那里:

  1. 访问包的首页
  2. 单击导出的模块树列表中的任何模块名称
  3. 在右上角有链接Source | Contents | Index | Style。单击索引链接。
  4. 什么是St

    St定义为

    type St r = RWS () Text Int r
    

    RWS只是一个具有Reader,Writer和State功能的monad。 Reader环境为(),它为Text值写入,Int为州。

    这是一个方便的定义(可从mtl包中获得),因此您不必使用ReaderTWriterTStateT构建自己的monad转换器堆栈

    请注意,阅读器环境为(),这意味着库实际上只使用了monad的编写器和状态方面。

    box ... >= box ...如何运作?

    box函数的类型为:

    box :: Selector -> (Double, Double) -> St (Var' Selection)
    

    这意味着需要Select和一对双打,并在Var' Selector monad中返回St

    表达式box "#div1" (300,300) >>= bars n 300 (Data1D [...])与:

    相同
    do vs <- box "#div1" (300,300)
       bars n 300 (Data1D [...]) vs
    

    解读:

    1. 运行box功能以创建Var' Selection。这发生在St monad。
    2. 使用步骤1返回的bars致电Var' Selection
    3. Var' SelectionSelection之间有什么区别?老实说,我不确定。

      >>>运算符

      >>>是一个Arrow运算符。箭头是一种将计算表达为操作管道的方法。本页面上的示例应该让您了解它是如何使用的:

      https://www.haskell.org/arrows/syntax.html

      请注意,>>>是根据类型类定义的,所以它的确切取决于您使用它的类型。在这种情况下,它与Chain () Selection值一起使用。

      如果你阅读了Chain (link)的文档,你会看到评论:

        

      链a b的行为就像(a - &gt; 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
      

      可以理解为:

      1. 从d3对象开始。这将返回一个选择。
      2. 选择该选择的父级。
      3. 使用参数append
      4. 调用JS函数"svg"
      5. 设置宽度,然后设置高度,然后设置样式
      6. 有趣的是func函数的类型为Chain a b - 它具有不受限制的返回类型b。这就是为什么我怀疑最后有明确的类型签名,例如:: Chain () Selection

答案 1 :(得分:1)

正如@delta已经说过hoogle是你的朋友 - 这里导入的作品来自Control.Category - 它表示态射的从左到右的构图。< / p>

在这种情况下,手头的类别是与monad相关的 Kleisli类别只是 Hask 的子类别 - 然后>>>运算符是缺少链接以制作

等功能
 f :: m a -> m b
 g :: m b -> m c

彼此正常工作。而

>>= :: m a -> (a -> m b) -> m b

无法做到这一点,专业版(&gt;&gt;&gt;)

>>> :: (m a -> m b) -> (m b -> m c) -> ma -> m c

会为您h = (f >>> g)提供正确的输出。