我一直在阅读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 我在哪里可以找到类型签名或其他基本信息? 是否有资源我可以了解更多:
$
Haskell: difference between . (dot) and $ (dollar sign) >>>
这可能是arrow,但我不知道我在哪里导入它。>>=
第一个很容易找到,但答案令人困惑:
*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)
答案 0 :(得分:3)
包索引
Hackage上的软件包通常有一个定义了所有函数/类型/等的索引页。 d3js包的索引位于:
你可以通过以下方式到达那里:
Source | Contents | Index | Style
。单击索引链接。 什么是St
?
St
定义为
type St r = RWS () Text Int r
RWS
只是一个具有Reader,Writer和State功能的monad。 Reader环境为()
,它为Text
值写入,Int
为州。
这是一个方便的定义(可从mtl
包中获得),因此您不必使用ReaderT
,WriterT
和StateT
构建自己的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
解读:
box
功能以创建Var' Selection
。这发生在St
monad。bars
致电Var' Selection
。 Var' Selection
和Selection
之间有什么区别?老实说,我不确定。
>>>
运算符
>>>
是一个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
可以理解为:
append
"svg"
有趣的是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)
提供正确的输出。