【问题标题】:How do the operators `>>>` and `>>=` work in Haskell?运算符 `>>>` 和 `>>=` 在 Haskell 中是如何工作的?
【发布时间】:2016-09-16 15:45:12
【问题描述】:

我一直在阅读 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 对涉及单子的>>= 给出了类似的响应。就我而言,它可能是 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)

【问题讨论】:

  • &gt;&gt;&gt; 现在实际上是在Control.Category 中定义的。 (CategoryArrow 的超类。)
  • 关于你的最后一个问题——我想请你回答一个反问题——你对此有什么理解——以及什么给你带来了问题。你看过每种类型的定义吗?
  • 作为一个不错的技巧,如果你有一个&gt;&gt;&gt; 链,你可以在任何点添加一个“洞”,例如将x1 &gt;&gt;&gt; x2 &gt;&gt;&gt; x3 更改为x1 &gt;&gt;&gt; _ &gt;&gt;&gt; x2 &gt;&gt;&gt; x3。这将使 GHC 在编译期间引发 error ,并携带应该在孔中使用的类型。您可以在 Hoogle 上查找该类型,并查看 &gt;&gt;&gt; 是什么。 (&gt;&gt;= 或其他许多事情同上)。
  • @chepner 好的,我在 Hoogle 上找到了 &gt;&gt;&gt;。你知道这里可能使用哪个类别吗?这个箭头&gt;&gt;&gt; 会自动知道吗?

标签: haskell monads category-theory


【解决方案1】:

包索引

Hackage 上的包通常有一个定义所有功能/类型/等的索引页面。 d3js 包的索引位于此处:

你可以通过:

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

什么是St

St 定义为

type St r = RWS () Text Int r

RWS 只是一个具有 Reader、Writer 和 State 能力的 monad。 Reader 环境是(),它写入Text 值和Int 用于状态。

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

请注意,阅读器环境是 (),这意味着库仅真正使用了 monad 的编写器和状态方面。

box ... &gt;= box ... 是如何工作的?

box 函数的类型为:

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

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

表达式box "#div1" (300,300) &gt;&gt;= bars n 300 (Data1D [...]) 等同于:

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

解读:

  1. 运行box 函数以创建Var' Selection。这发生在 St monad 中。
  2. 使用步骤 1 返回的 Var' Selection 调用 bars

Var' SelectionSelection 有什么区别?老实说,我不确定。

&gt;&gt;&gt; 运算符

&gt;&gt;&gt; 是箭头运算符。箭头是将计算表示为操作管道的一种方式。此页面上的示例应该让您了解它的使用方式:

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

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

如果您阅读 Chain (link) 的文档,您会看到以下评论:

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

可以读作:

  1. 从 d3 对象开始。这会返回一个选择。
  2. 选择该选择的父项。
  3. 使用参数"svg"调用JS函数append
  4. 先设置宽度,然后设置高度,然后设置样式

有趣的是func 函数有Chain a b 类型——它有一个不受限制的返回类型b。这就是为什么我怀疑最后有明确的类型签名,例如:: Chain () Selection.

【讨论】:

    【解决方案2】:

    @delta 已经说过 hoogle 是你的朋友 - 这里的导入片段来自 Control.Category - 它表示态射的从左到右的组合

    在这种情况下,当前的类别是与 monad 关联的 Kleisli 类别 只是 Hask 的子类别 - 然后 &gt;&gt;&gt; 运算符是 缺少链接来制作像

    这样的功能
     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 &gt;&gt;&gt; g)一个正确的输出。

    【讨论】:

    • 我不会打电话给m a -&gt; m bKleisli。它只是 Hask 的一个子类别。 a -&gt; m b 将是 Kleisli。实际上&gt;&gt;=(更准确地说是&gt;=&gt;)以普通函数形式组成Kleisli箭头,但&gt;&gt;&gt;只能将它们组成their wrapped form
    • 哦 - 这是我长期以来的误解 - 谢谢你告诉我
    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 2021-10-12
    • 2016-10-25
    • 2020-01-29
    • 1970-01-01
    • 2011-10-08
    相关资源
    最近更新 更多