2
votes

I have been reading through a Haskell d3js library:

This is the code defining Haskell box:

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)

The code actually exporting using the box function in d3.js code uses the >>= operator like this:

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]))

To avoid being like this unpopular question on arrows: How to use arrow operators in haskell Where can I find the type signatures, or other basic information? Are there resources where I can learn more about:

The first one was easy to find but the answer was confusing:

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

I found that f $ a b c = f ( (a b) c ) while f a b c = (((f a) b) c

Prelude gives a similar response for >>= involving monads. In my case, it might be the IO monad. Or the d3js statement monad St()

*Main Lib> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b

The last one doesn't show up at all... which is too bad because it looks pretty essential

*Main Lib> :t (>>>)

<interactive>:1:1:
    Not in scope: ‘>>>’
    Perhaps you meant one of these:
      ‘>>’ (imported from Prelude), ‘>>=’ (imported from Prelude)

Lastly at the risk of bundling too many questions at once. Can someone explain this type signature? Especially the last item:

box :: Selector ->  (Double,Double) -> St (Var' Selection)
2
>>> is actually defined in Control.Category now. (Category is the superclass of Arrow.)chepner
Regarding your last question - I would ask you to answer a counter question - what have you understood about it - and what is giving you problems. Have you looked at the definitions of each type?epsilonhalbe
As a nice trick, if you have a chain of >>>, you can add a "hole" at any point e.g. change x1 >>> x2 >>> x3 into x1 >>> _ >>> x2 >>> x3. This will make GHC raise an error during compilation, carrying the type which should be used in the hole. You can look up that type on Hoogle, and see what >>> is. (Ditto for >>=, or many other things).chi
@chepner OK I found >>> on Hoogle. Do you know which category might be used here? Does this arrow >>> know that automatically?john mangual

2 Answers

3
votes

The package Index

Packages on Hackage usually have an index page of all functions / types / etc. defined. The index for the d3js package is located here:

You can get there by:

  1. Visit the front page for the package
  2. Click on any module name in the exported module tree list
  3. In the upper right hand corner there are the links Source | Contents | Index | Style. Click on the Index link.

What is St?

St is defined as

type St r = RWS () Text Int r

RWS is just a monad which has Reader, Writer and State capabilities. The Reader environment is (), it writes Text values and an Int for state.

It's a convenience definition (available from the mtl package) so you don't have to build up your own monad transformer stack using ReaderT, WriterT and StateT.

Note that the reader environment is () which means that library is only really using the writer and state aspects of the monad.

How does box ... >= box ... work?

The box function has type:

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

which means it takes a Select and a pair of Doubles and returns a Var' Selector in the St monad.

The expression box "#div1" (300,300) >>= bars n 300 (Data1D [...]) is the same as:

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

Interpretation:

  1. Run the box function to create a Var' Selection. This happens in the St monad.
  2. Call bars with the Var' Selection returned by step 1.

What's the difference between a Var' Selection and a Selection? Honestly I'm not sure.

The >>> operator

>>> is an Arrow operator. Arrows is a way of expressing computations as a pipeline of operations. The examples on this page should give you an idea of how it's used:

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

Note that >>> is defined in terms of a type-class, so exactly what it does depends on what types you are using it with. In this case it is being used with Chain () Selection values.

If you read the docs for Chain (link) you'll see the comment:

Chain a b behaves just like (a -> b). Val Var is the starting point of chain (= constant), and Nil is the termination of chain.

So this fragment:

                                            -- 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

can be read as:

  1. Start with the d3 object. This returns a selection.
  2. Select the parent of that selection.
  3. Call the JS function append with argument "svg"
  4. Set the width then the height and then the style

What's interesting is that the func function has type Chain a b -- it has an unrestricted return type b. That's why I suspect there is the explicit type signature at the end, e.g. :: Chain () Selection.

1
votes

as @delta already said hoogle is your friend - the imported piece here is from Control.Category - and it denotes the Left-to-right composition of morphisms.

The category at hand in this case is the Kleisli Category associated to a monad just a sub-category of Hask - then the >>> operator is the missing link to make functions like

 f :: m a -> m b
 g :: m b -> m c

work properly with each other. while

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

would not be able to do that, the specialized version of (>>>)

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

would give you h = (f >>> g) a correct output.