[Haskell] [ANN] shapely-data v0.1

2013-12-23 Thread Brandon Simmons
This is the first *real* release `shapely-data`, a haskell library
up here on hackage:

http://hackage.haskell.org/package/shapely-data

for working with algebraic datatypes in a simple generic form made up of
haskell's primitive product, sum and unit types: `(,)`, `Either`, and `()`.

You can install it with

cabal install shapely-data

# Motivation and examples

In order from most to least important to me, here are the concerns that
motivated the library:

- Provide a good story for `(,)`/`Either` as a *lingua franca* generic
  representation that other library writers can use without dependencies,
  encouraging abstractions in terms of products and sums (motivated
  specifically by my work on
  `simple-actors`: http://hackage.haskell.org/package/simple-actors

- Support algebraic operations on ADTs, making types composable

-- multiplication:
let a = (X,(X,(X,(
b = Left (Y,(Y,())) :: Either (Y,(Y,())) (Z,())
ab = a >*< b
 in ab == ( Left (X,(X,(X,(Y,(Y,())
:: Either (X,(X,(X,(Y,(Y,()) (X,(X,(X,(Z,() )

-- exponents, etc:
fanout (head,(tail,(Prelude.length,( [1..3]== (1,([2,3],(3,(
(unfanin (_4 `ary` (shiftl . Sh.reverse)) 1 2 3 4) == (3,(2,(1,(4,()

- Support powerful, typed conversions between `Shapely` types

data F1 = F1 (Maybe F1) (Maybe [Int]) deriving Eq
data F2 = F2 (Maybe F2) (Maybe [Int]) deriving Eq
f2 :: F2
f2 = coerce (F1 Nothing $ Just [1..3])

data Tsil a = Snoc (Tsil a) a | Lin deriving Eq
truth = massage "123" == Snoc (Snoc (Snoc Lin '3') '2') '1'

Lowest on the list is supporting abstracting over different recursion schemes
or supporting generic traversals and folds, though some basic support is
planned.

Finally, in at least some cases this can completely replace `GHC.Generics` and
may be a bit simpler. See `examples/Generics.hs` for an example of the
`GHC.Generics` wiki example:

http://www.haskell.org/haskellwiki/GHC.Generics

...ported to `shapely-data`. And for a nice view on the changes that were
required, do:

git show 3a65e95 | perl
/usr/share/doc/git/contrib/diff-highlight/diff-highlight


## Why not GHC.Generics?

The `GHC.Generics` representation has a lot of metadata and a complex
structure that can be useful in deriving default instances; more important to
us is to have a simple, canonical representation such that two types that
differ only in constructor names can be expected to have identical generic
representations.

This supports APIs that are type-agnostic (e.g. a database library that returns
a generic `Product`, convertible later with `to`), and allows us to define
algebraic operations and composition & conversion functions.


Happy Holidays, everybody!
Brandon
___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell


[Haskell] ANNOUNCE: PEZ, the Potentially Excellent Zipper library

2011-04-22 Thread Brandon Simmons
I'm happy to present my long-languishing-on-the-harddrive generic
zipper library I'm calling pez:

   http://hackage.haskell.org/package/pez

The library brings together the 'fclabels' and 'thrist' packages with
the Typeable class to enable a zipper library that is (I hope)
intuitive and requiring a minimum of boilerplate. Get it with:

   $ cabal install pez

There is still much to do, in particular I have not looked at the
performance characteristics of this approach at all, but I hope others
find it interesting or useful. Please send any feature requests, or
bug reports.


  EXAMPLE USAGE


First you need to enable some extensions, the first two for generating
and using 'fclabels' lenses, the second for easy deriving of Typeable
instances on custom types:

> {-# LANGUAGE TemplateHaskell, TypeOperators, DeriveDataTypeable #-}
>
> module Main where
>
> -- import pez
> import Data.Typeable.Zipper
> -- for prettiness:
> import Control.Arrow
> import Control.Applicative

Now we define a tree that we want to use in our zipper. We want it to be an
instance of Typeable which we can derive, and we want 'fclabels' lenses to be
generated with TH for the branches, so we name the records with underdashes
(see:  http://hackage.haskell.org/package/fclabels )

> data Tree a = Node {
>  _leftNode :: Tree a,
>  _val  :: a,
>  _rightNode :: Tree a }
> | Nil
> deriving (Typeable,Show)
>
> $(mkLabelsNoTypes [''Tree])

At this point we can use all of our zipper functions on the Tree type. The
following returns the value at the left-most Node, along with a SavedPath back
to that Node. It returns Nothing if the tree is empty:

> -- 'a' must be Typeable because we actually "moveTo" it here:
> getLeftmost :: Typeable a=> Tree a -> Maybe (a, SavedPath (Tree a) a)
> getLeftmost = fmap (viewf &&& save) . descendLeft . zipper
> where descendLeft z =
>   case viewf z of
>Nil -> moveTo val <$> moveUp 1 z
>_   -> descendLeft $ moveTo leftNode z

A `SavedPath` can be restored moving the focus back to the location it points
to, or it can be collapsed into a lens itself.

Let's use the function we defined above to make sure it works:

> tree = Node (Node Nil 'a' Nil) 'b' (Node Nil 'c' Nil)
>
> main = do
> putStr "This should show 'a': "
> putStrLn $ maybe "FAIL" (show . fst) $ getLeftmost tree

You can also experiment with "zipping through" computations. It's as
simple as defining a new fclabel lens for a reversible computation,
e.g.:

> reversible :: (Show b, Read b) => b :-> String
> reversible = lens show (const . read)

Thanks,
Brandon Simmons
http://coder.bsimmons.name

___
Haskell mailing list
Haskell@haskell.org
http://www.haskell.org/mailman/listinfo/haskell