HList-0.3.0.1: Heterogeneous lists

Safe HaskellNone

Data.HList.CommonMain

Contents

Description

The HList library

This module re-exports everything needed to use HList.

Synopsis

Documentation

Data.HList.Keyword

the "public" parts. More examples are in the module documentation.

class Kw fn arg_def r whereSource

kw takes a HList whose first element is a function, and the rest of the elements are default values. A useful trick is to have a final argument () which is not eaten up by a label (A only takes 1 argument). That way when you supply the () it knows there are no more arguments (?).

>>> data A = A
>>> instance IsKeyFN (A -> a -> b) True
>>> let f A a () = a + 1
>>> let f' = f .*. A .*. 1 .*. HNil
>>> kw f' A 0 ()
1
>>> kw f' ()
2

Methods

kw :: HList (fn : arg_def) -> rSource

Instances

(KW' Bool rflag fn akws arg_def r, ~ * akws (Arg [*] kws ([] *)), ReflectFK' * [*] flag fn kws, IsKeyFN * r rflag, IsKeyFN * fn flag) => Kw fn arg_def r 

recToKW :: forall a b. (HMapAux LVPairToKW a b, SameLength a b, SameLength b a, HConcat b) => Record a -> HList (HConcatR b)Source

convert a Record into a list that can supply default arguments for kw

A bit of setup:

>>> :set -XQuasiQuotes
>>> let f (_ :: Label "a") a (_ :: Label "b") b () = a `div` b
>>> let a = 2; b = 1; f' = f .*. recToKW [pun| a b |]
>>> kw f' ()
2
>>> kw f' (Label :: Label "a") 10 ()
10

class IsKeyFN t flag | t -> flagSource

All our keywords must be registered

Instances

~ Bool False flag => IsKeyFN k t flag

overlapping/fallback case

IsKeyFN * (Label Symbol s -> a -> b) True

labels that impose no restriction on the type of the (single) argument which follows

>>> let testF (_ :: Label "a") (a :: Int) () = a+1
>>> kw (hBuild testF) (Label :: Label "a") 5 ()
6
~ * r (c -> b) => IsKeyFN * (K k s c -> r) True

The purpose of this instance is to be able to use the same Symbol (type-level string) at different types. If they are supposed to be the same, then use Label instead of K

>>> let kA = K :: forall t. K "a" t
>>> let testF (K :: K "a" Int) a1 (K :: K "a" Integer) a2 () = a1-fromIntegral a2

therefore the following options works:

>>> kw (hBuild testF) kA (5 :: Int) kA (3 :: Integer) ()
2
>>> kw (hBuild testF) (K :: K "a" Integer) 3 (K :: K "a" Int) 5 ()
2

But you cannot leave off all Int or Integer annotations.

data K s c Source

Instances

~ * r (c -> b) => IsKeyFN * (K k s c -> r) True

The purpose of this instance is to be able to use the same Symbol (type-level string) at different types. If they are supposed to be the same, then use Label instead of K

>>> let kA = K :: forall t. K "a" t
>>> let testF (K :: K "a" Int) a1 (K :: K "a" Integer) a2 () = a1-fromIntegral a2

therefore the following options works:

>>> kw (hBuild testF) kA (5 :: Int) kA (3 :: Integer) ()
2
>>> kw (hBuild testF) (K :: K "a" Integer) 3 (K :: K "a" Int) 5 ()
2

But you cannot leave off all Int or Integer annotations.

Labels

there are really only two options for now, but there are a couple different styles for the first option here:

GHC supports type-level strings (Symbol), and these can be labels. You can refer to these strings using an unwieldy syntax. For example if you want to store a value 5 in a record rec with a field called "x", and then get it out again:

let rec = (Label :: Label "x") .=. 5 .*. emptyRecord

rec .!. (Label :: Label "x")

To avoid that pain, you can have a definition x = Label :: Label x. and just use x instead of repeating Label :: Label "x" so that a lookup becomes:

 rec .!. x

See makeLabels6 for automating the x = Label :: Label "x".

Instances from Data.HList.Label6

>>> :set -XDataKinds
>>> (Label :: Label "x") .=. (5::Int) .*. emptyRecord
Record{x=5}
>>> let x = Label :: Label "x"
>>> let r = x .=. (5::Int) .*. emptyRecord
>>> r .!. x
5

Rather than having the x = Label :: Label "x", the labels generated by makeLabelable also double lenses for Control.Lens. Here is an example of how much better that is:

>>> :set -XNoMonomorphismRestriction -XDataKinds -XPolyKinds
>>> import Control.Lens
>>> let x = hLens' (Label :: Label "x")

The Label6 method:

>>> let r = (Label :: Label "x") .=. "5" .*. emptyRecord

The Labelable way:

>>> let r2 = x .==. "5" .*. emptyRecord
>>> r ^. x
"5"
>>> r2 ^. x
"5"
>>> r & x .~ ()
Record{x=()}

namespaced labels

template haskell for automating different types of labels

quasiquoter pun helps to avoid needing a proxy value with type Label in the first place: when you take values out of or into records with pattern matching, the variable name determines the label name.

Data.HList.Data

This modules provide useful instances. A useful application can be found in examples/cmdargs.hs