[Haskell-cafe] Flexible Wrappers - an Introduction
Iain Alexander
ia at stryx.demon.co.uk
Sat Mar 12 03:09:14 CET 2011
There are three flexible wrappers provided in the initial flexiwrap package
[1]. (More may be required in the future.)
short long wraps
FW FlexiWrap values
FWT FlexiWrapT unary type constructors
FWCTC FlexiWrapCTC binary operators which combine two
unary type constructors
The short names are frequently convenient since type signatures can get quite
long. The suffixes are a simple encoding of the kind of the wrapped quantity,
description of which I defer to a later post.
The first parameter to each of these is a phantom - it plays no part in the
implementation type, but serves as an index to generate multiple distinct types
from each wrapper. In addition, by using a type-level list here, we can use it
to specify any number of instance implementations.
By way of a rather contrived but simple example, the module
Data.Flex.SmallCheck.Wrap implements and uses an instance selector called
FWEqFirst to implement an Eq instance which compares pairs by their first
element. It is used there by defining a type
FW (FWEqFirst :*: TNil) (Bool, Bool)
which has the requisite properties.
The initial proof-of-concept version of the package provides only a limited
number of instance selectors (with the associated machinery) for each wrapper.
FW (in Data.Flex.Wrap) has only an implementation for Eq instances, with
FWDefaultEq to explicitly specify the default implementation which simply
delegates to the underlying wrapped type.
FWT (Data.Flex.WrapT) has
FWTDefaultFunctor (Functor)
FWTDefaultApplicative (Applicative)
FWTDefaultMonadAll (the combination of FWTDefaultMonad and
FWTDefaultMonadState)
FWTDefaultMonad (Monad)
FWTDefaultMonadState (MonadState)
which all again delegate to the underlying type.
There is also a separate module Data.Flex.WrappedMonad which provides selectors
to implement Functor and Applicative instances for a Monad which lacks them.
FWWrapMonad (the combination of FWMonadFunctor and FWMonadApplicative)
FWMonadFunctor (Monad => Functor)
FWMonadApplicative (Monad => Applicative)
FWCTC (Data.Flex.WrapCTC) has
FWCTCDefaultFunctor (Functor)
FWCTCDefaultMonad (Monad)
which simply delegate to the application of the wrapped binary operator to two
constructor arguments, but provides underlying machinery for these together
with MonadPlus and MonadTrans.
Data.Flex.Compose contains the (:.) (alias O) type composition operator as
found in e.g. the TypeCompose package [2]. It contains a fairly literal
translation of Mark Jones and Luc Duponcheel's scheme for monad composition
[3],
FWCompP - use the "prod" construction
FWCompD - use the "dorp" construction
FWCompS - use the "swap" construction
and selectors for MonadTrans and MonadPlus
FWCompDefaults (the combination of FWCompTrans and FWCompMonadPlus)
FWCompTrans (MonadTrans)
FWCompMonadPlus (a synonym for FWCompMonadPlusR)
FWCompMonadPlusR (using the MonadPlus instance of the right-hand
argument of the composition)
FWCompMonadPlusL (using the MonadPlus instance of the left-hand
argument of the composition)
Data.Flex.FlipT contains the operator FlipT which flips the arguments of an
operator such as (:.).
FWFlipDefaults (the combination of FWFlipMonad and FWFlipMonadPlus)
FWFlipMonad (Monad)
FWFlipMonadPlus (MonadPlus)
These delegate the implementation to the underlying binary operator, which it
wraps with FWCTC, passing the phantom selector list along.
So, to recap the example given in the package release announcement:
data FWStrict = FWStrict
type Strict = FW (FWStrict :*: TNil)
type StrictT = FWCTC
(FWFlipDefaults :*:
FWCompMonadPlusL :*: FWCompDefaults :*: FWCompS :*: TNil
)
(FlipT O) Strict
defines a (e.g. monad, but in general constructor) transformer StrictT. FWCTC
is a flexible wrapper. Its first parameter is an HList-like type-level list of
instance specifications. O is the type composition operator, and FlipT flips
its arguments. Strict is a user-defined wrapper type. (This is strict vs.
loose, not strict vs. lazy. It is intended to be used to wrap values of a data
structure which satisfy certain criteria.) FWCompMonadPlusL specifies a
particular MonadPlus instance (which delegates to the left operand of the
composition, which is the right operand of the flipped composition, i.e.
whatever argument you pass to StrictT), and FWCompS specifies the
Jones/Duponcheel SComp construction [3]. The other two items in the list
(apart from the TNil terminator) specify default implementations of other
instances.
[1] http://hackage.haskell.org/package/flexiwrap-0.0.1
[2] http://hackage.haskell.org/package/TypeCompose
[3] http://web.cecs.pdx.edu/~mpj/pubs/RR-1004.pdf
More information about the Haskell-Cafe
mailing list