simple-actors 0.1.0 released

11/10/2011

Just a quick announcement of the release of simple-actors, a DSL-style haskell library for more structured concurrent programs via the Actor Model. You can fork it on github, and install it via cabal with a

cabal install simple-actors

This version is significantly more coherent, powerful and simple than the original 0.0.1 version (which was something I just whipped together for a blog post I haven’t gotten around to writing yet).

Let me know if you have any comments or suggestions!

No Comments

A brief tutorial-introduction to ‘fclabels’ 1.0

21/08/2011

Sebastiaan Visser et al. last week announced the release of v1.0 of fclabels. This is a short introduction to the changes for people who are already somewhat familiar with the package.

Que? The fclabels package is a haskell library providing “first class labels” for haskell data types and some Template Haskell code for automatically generating said labels. This makes for a more composable and much more powerful alternative to haskell’s built-in record syntactic sugar. Here is a good introductory tutorial.

The new version features (besides some better names) a type for lenses that can fail. S.V. et al. added this functionality in a brilliant and mostly (except for the name changes) backwards compatible way. We’ll see how it all works now.

We’ll prepare a module for fclabels in the usual way:


{-# LANGUAGE TemplateHaskell, TypeOperators #-}
import Control.Category
import Data.Label
import qualified Data.Label.Maybe as M
import Prelude hiding ((.)id)

The only odd thing above is our qualified import of Data.Label.Maybe which provides getters, setters etc. that can fail.

We want to generate lenses for the following type, so we do the underdash thing:


36 data Example = X { _int :: Int , _char :: Char}
37              | Y { _int :: Int , _example :: Example }

Notice how _int is a valid record for both constructors X and Y, where the other two are partial functions.

Lastly, the usual splice for generating labels:


39 $(mkLabels[''Example])

Let’s load our file into GHCi and play a little:

Prelude> :l test.hs
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> get int $ X 1 'a'
1
*Main> M.get int $ X 1 'a'
Just 1
*Main> M.get char $ X 1 'a'
Just 'a'
*Main> M.get example $ X 1 'a'
Nothing
*Main> get example $ X 1 'a'

:1:5:
    No instance for (Control.Arrow.ArrowZero (->))
      arising from a use of `example'
    Possible fix:
      add an instance declaration for (Control.Arrow.ArrowZero (->))
    In the first argument of `get', namely `example'
    In the expression: get example
    In the expression: get example $ X 1 'a'

Above we saw that:

  • the total int label could be used in both get and Data.Label.Maybe.get
  • M.get on our “partial lenses” (example and char) safely returned a Maybe value.
  • pure get used with partial lenses doesn’t type check

We need to look at some types (note I’ve cleaned up some of these type signatures, yours may look uglier):

*Main> :t get
get :: (f :-> a) -> f -> a
*Main> :t M.get
M.get :: (f M.:~> a) -> f -> Maybe a
*Main> :info (:->)
type (:->) f a = Data.Label.Pure.PureLens f a
  	-- Defined in Data.Label.Pure
*Main> :info (M.:~>)
type (M.:~>) f a = Data.Label.Maybe.MaybeLens f a
  	-- Defined in Data.Label.Maybe

You can see above that setters and getters are monomorphic. But how then were we able to use int in both get and M.get? Time to look at the types of our TH-generated lenses:

*Main> :t int
int
  :: Control.Arrow.Arrow (~>) => Lens (~>) Example Int
*Main> :t char
char
  :: (Control.Arrow.ArrowZero (~>),
      Control.Arrow.ArrowChoice (~>)) =>
     Lens (~>) Example Char
*Main> :t example
example
  :: (Control.Arrow.ArrowZero (~>),
      Control.Arrow.ArrowChoice (~>)) =>
     Lens (~>) Example Example

Whoah! Lenses themselves are polymorphic in the Arrow class; partial lenses have additional restrictions of ArrowZero and ArrowChoice allowing for failure and choice.

This is wizardry of the highest order.

Notice how we can still compose lenses freely, whether partial or total:

*Main> :t (.)
(.) :: Category cat => cat b c -> cat a b -> cat a c
*Main> M.get (int . example) (Y 1 (X 2 ‘a’))
Just 2

A note on mkLabelsNoTypes

I had been using the noTypes variation to generate lenses that I was exporting in a module, because the TH-assigned type sigs looked pretty nasty. If you do this with >1.0 you will run into the monomorphism restriction and ambiguous type variables.

Instead I would suggest defining exported lables by hand and giving them a nicer looking (or monomorphic if you prefer) type sig.

You can even let fclabels generate the code and just paste it in, e.g.:

Prelude> :set -ddump-splices
Prelude> :l test.hs
[1 of 1] Compiling Main             ( test.hs, interpreted )
test.hs:1:1: Splicing declarations
    mkLabels ['Example]
  ======>
    test.hs:40:3-21
    char ::
      forall ~>[a1kk]. (Control.Arrow.ArrowChoice ~>[a1kk],
                        Control.Arrow.ArrowZero ~>[a1kk]) =>
      Lens ~>[a1kk] Example Char
    {-# INLINE[0] CONLIKE char #-}
    char
      = let
          c[a1kl]
            = (Control.Arrow.zeroArrow Control.Arrow.||| Control.Arrow.returnA)
        in
          Data.Label.Abstract.lens
            (c[a1kl]
           . Control.Arrow.arr
               (\ p[a1km]
                  -> case p[a1km] of {
                       X {} -> Right (_char p[a1km])
                       _ -> Left GHC.Unit.() }))
            (c[a1kl]
           . Control.Arrow.arr
               (\ (v[a1kn], p[a1ko])
                  -> case p[a1ko] of {
                       X {} -> Right (p[a1ko] {_char = v[a1kn]})
                       _ -> Left GHC.Unit.() }))
...
No Comments

Module ‘chan-split’ released

17/07/2011

Whaa?

chan-split is a haskell library that is a wrapper around Control.Concurrent.Chans that separates a Chan into a readable side and a writable side.

We also provide two other modules: Data.Cofunctor (because there didn’t seem to be one anywhere), and Control.Concurrent.Chan.Class. The latter creates two classes: ReadableChan and WritableChan, making the fundamental chan functions polymorphic, and defining an instance for standard Chan as well as MVar (an MVar is a singleton bounded channel, wanna fight about it?).

Why?

Having separate read/write sides makes it easier to reason about your code, supports doing some cool things (defining Functor and Cofunctor instances), and makes more sense (e.g. the function of dupChan in the base library is much easier to understand as an operation that happens on an OutChan).

Also I use it in (the coming new, less stupid version of) my module simple-actors.

Where?

You can get it with a:

cabal install chan-split

And check out the docs on hackage. Or check out the source on github and send me pull requests.

Usage

Let’s write the numbers 1 – 10 to the InChan and read them as a stream in the OutChan:


 1 module Main
 2     where
 3 
 4 import Control.Concurrent.Chan.Split
 5 import Control.Concurrent(forkIO)
 6 
 7 main = do
 8     -- Instead of a single Chan, we initialize a pair of (InChan,OutChan)
 9     (inC,outC) <- newSplitChan
10     -- fork a writer on the InChan
11     forkIO $ writeStuffTo inC [1..10]
12     -- read from the OutChan in the main thread:
13     getStuffOutOf outC >>=
14       mapM_ print . take 10 

And we’ll make writeStuffTo and getStuffOutOf, simply be the standard functions. Note that writeListToChan is actually polymorphic.


16 writeStuffTo :: InChan Int -> [Int] -> IO ()
17 writeStuffTo = writeList2Chan
18 
19 getStuffOutOf :: OutChan Int -> IO [Int]
20 getStuffOutOf = getChanContents

Now I’ll demonstrate the use of our Functor and Cofunctor instances by re-defining those two functions above, after importing our Cofunctor class


17 import Data.Cofunctor
18 
19 ...
20 
21 -- we could convert the [Int] to [String] here but will instead demonstrate the
22 -- Cofmap instance:
23 writeStuffTo :: InChan String -> [Int] -> IO ()
24 writeStuffTo = writeList2Chan . cofmap show
25 
26 -- likewise this demonstrates the Functor instance of OutChan:
27 getStuffOutOf :: OutChan String -> IO [Int]
28 getStuffOutOf = getChanContents . fmap read

All right, leave your love or hate and stay tuned for the new (less stupider) simple-actors lib.

No Comments