Flexible Wrappers - an Introduction

Previous Topic Next Topic
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Flexible Wrappers - an Introduction

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

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

[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

Haskell-Cafe mailing list
[hidden email]