Safe Haskell | None |
---|---|

Language | Haskell98 |

This modules provides a convienient way to access and update the elements of a structure.
It is very similar to Data.Accessors, but a bit more generic and has fewer dependencies.
I particularly like how cleanly it handles nested structures in state monads.
`runSTLense`

is also a very useful function.

A brief tutorial to get started:

To create a lense, you can use fromGetSet (although usually you would just derive them using templat haskell and `deriveLenses`

from Data.Lenses.Template):

lense = fromGetSet getField setField

The lense has type:

lense :: (MonadState r m) => StateT a m b -> m b

Where r is the type of the record, and a is the type of the field, (b can be any type you choose, more on that latter). Though it may help to think of it as:

lense :: State a b -> State r b

Which is not entirely accurate, but emphasises how the lense works. You can think of it as "pass in an action that operates on the field, and you get an action that operates on the record". So say we pass in get (with a more specific type for clarity):

get :: State a a lense get :: State r a

We get out a state monad that we can run on our record to fetch our field.

fieldValue = lense get `evalState` record

This module has a special function `fetch`

that does this:

fieldValue = record `fetch` lense

You can also pass in `put`

to get back an action that updates the field.

put :: a -> State a () lense (put someValue) :: State r ()

Now we have a state monad that we can run on our record to update our field.

updatedRecord = lense (put someValue) `execState` record

This module has a special function `update`

that does this:

updatedRecord = (record `update` lense) someValue

To aid in clarity and to deal with the actual types of the lenses this module provides `execIn`

, `evalFrom`

, and `runOn`

to be used in place of `execState`

, `evalState`

, and `runState`

. Also note that `execIn`

, `evalFrom`

, and `runOn`

have their parameters fliped from their state counterparts. There is nothing magical about these functions, they are just a little more handy than their state counterparts.

The lenses are especially convienient if you have nested structures. Lense composition is just function composition.

data Point = Point { x_ :: Float, y_ :: Float } deriving (Show)

$( deriveLenses ''Point )

data Triangle = Triangle { pa_ :: Point, pb_ :: Point, pc_ :: Point } deriving (Show)

$( deriveLenses ''Triangle )

a_y :: (MonadState Triangle m) => StateT Float (StateT Point m) b -> m b a_y = pa . y

a_y is now a lense that can operate on the y coordinate of point "a" inside a triangle. We can use a_y to fetch the coordinate or update it, on whatever triangle we choose.

someTriangle = Triangle (Point 5 3) (Point 0 1) (Point 10 6) ayValue = someTriangle `fetch` a_y -- ayValue == 3 updatedTriangle = (someTriangle `update` a_y) 7 -- updatedTriangle == Triangle (Point 5 7) (Point 0 1) (Point 10 6)

Or we could apply our lense to an action and pass it into `execIn`

(someTriangle `update` a_y) 7 == execIn someTriangle (a_y (put 7))

We can also chain actions together:

a_x :: (MonadState Triangle m) => StateT Float (StateT Point m) b -> m b a_x = pa . x c_y :: (MonadState Triangle m) => StateT Float (StateT Point m) b -> m b c_y = pc . y updatedTriangle = execIn someTriangle $ a_y (put 7) >> a_x (put 1) >> c_y (put 9) -- updatedTriangle == Triangle (Point 1 7) (Point 0 1) (Point 10 9)

What if we wanted to put the value of c_y into a_x? Can do!

updatedTriangle = execIn someTriangle $ do cy <- c_y get a_x $ put cy -- updatedTriangle == Triangle (Point 6 3) (Point 0 1) (Point 10 6)

Or if the order really bugs you, you can use the `$%`

operator (taken from Data.Accessors.Basic, it really should be in a standard lib)

updatedTriangle = execIn someTriangle $ do cy <- get $% c_y put cy $% a_x -- updatedTriangle == Triangle (Point 6 3) (Point 0 1) (Point 10 6)

Or you can use the `$=`

operator:

updatedTriangle = execIn someTriangle $ do cy <- c_y get a_x $= cy

Or more concisely:

updatedTriangle = execIn someTriangle $ (c_y get >>= a_x . put)

Or say we want to put the value of c_y into a_x, but want to throw an error if c_y is zero. We can do that as well!

updatedTriangle :: Either String Triangle updatedTriangle = execInT someTriangle $ do cy <- c_y get when (cy == 0) $ throwError "Something bad happend" a_x $ put cy -- updatedTriangle == Right $ Triangle (Point 6 3) (Point 0 1) (Point 10 6) -- if cy had equaled 0 then we would have gotten this: -- updatedTriangle == Left "Something bad happend"

Note that `execInT`

= `flip`

`execStateT`

.

Yay for monad transformers!

This module has one last feature that allows you to convert a function that fetches data from a structure to a function that modifies it! For an example see the documentation for `runSTLense`

.

One final note: Due to the generality of the lenses you might end up accidentally running into the monomorphism restriction. So if get a type error like:

Couldn't match expected type `SomeMonad SomeStructureType' against inferred type `Control.Monad.Identity.Identity SomeStructureType'

and nothing appears to be wrong with your code, try turning the restriction off with -XNoMonomorphismRestriction and see if it goes away. If it does then you probably need to add some explicit type signatures somewhere.

I whipped out this documentation in a hurry, so if you spot any errors, or think I should explain something better, *please* let me know. This library is hosted on github (click on the *Contents* link above and you should see the Homepage link) so it should be very easy to forked it and send patches to me.
Also since this module is new I'm open to radical modifications if you have a good suggestion, so suggest away! :)

- fromGetSet :: MonadState r m => (r -> a) -> (a -> r -> r) -> StateT a m b -> m b
- fetch :: MonadState a m => r -> (m a -> StateT r Identity a) -> a
- update :: MonadState a m => r -> (m () -> StateT r Identity b) -> a -> r
- alter :: MonadState a m => (m () -> StateT r Identity b) -> (a -> a) -> r -> r
- runOn :: b -> StateT b Identity a -> (a, b)
- runOnT :: b -> StateT b m a -> m (a, b)
- evalFrom :: b -> StateT b Identity a -> a
- evalFromT :: Monad m => b -> StateT b m a -> m a
- execIn :: a -> StateT a Identity b -> a
- execInT :: Monad m => b -> StateT b m a -> m b
- runSTLense :: (Traversable f, Traversable t) => (forall s. f (State a b -> s) -> t s) -> f a -> (t b, f a)
- to :: Functor f => a -> (c -> f (a -> b)) -> c -> f b
- from :: (Traversable t, Traversable f) => (forall s. t (State a b -> s) -> f s) -> t a -> t a
- getAndModify :: MonadState s m => (s -> s) -> m s
- modifyAndGet :: MonadState s m => (s -> s) -> m s
- ($=) :: MonadState s m => (m () -> b) -> s -> b
- ($%) :: a -> (a -> b) -> b

# Basic functions to create lenses and use them

fromGetSet :: MonadState r m => (r -> a) -> (a -> r -> r) -> StateT a m b -> m b Source

This function takes a "getter" and "setter" function and returns our lense.

Usually you only need to use this if you don't want to use Template Haskell to derive your Lenses for you. With a structure Point:

data Point = Point { x_ :: Float, y_ :: Float } deriving (Show)

This (from Data.Lenses.Template):

$( deriveLenses ''Point )

is equivalent to this:

x :: (MonadState Point m) => StateT Float m b -> m b x = fromGetSet x_ (\a s -> s { x_ = a }) y :: (MonadState Point m) => StateT Float m b -> m b y = fromGetSet y_ (\a s -> s { y_ = a })

fetch :: MonadState a m => r -> (m a -> StateT r Identity a) -> a Source

fetches a field from a structure using a lense:

somePoint = Point 5 3 a = somePoint `fetch` x b = somePoint `fetch` y

-- a == 5 -- b == 3

update :: MonadState a m => r -> (m () -> StateT r Identity b) -> a -> r Source

updates a field in a structure using a lense:

somePoint = Point 5 3 newPoint = (somePoint `update` y) 15

-- newPoint == Point 5 15

alter :: MonadState a m => (m () -> StateT r Identity b) -> (a -> a) -> r -> r Source

alters a field in a structure using a lense and a function:

somePoint = Point 5 3 newPoint = (somePoint `alter` y) (+1)

-- newPoint == Point 5 4

# Lense evaluators

runOn :: b -> StateT b Identity a -> (a, b) Source

Runs a state monad action on a structure and returns the value returned from the action and the updated structure.

somePoint = Point 5 3 a = runOn somePoint $ x (modifyAndGet (+1)) -- a == (6, Point 6 3)

evalFrom :: b -> StateT b Identity a -> a Source

Runs a state monad action on a structure and returns the value returned from the action.

Use it to fetch values from fields.

someTriangle = Triangle (Point 5 3) (Point 0 1) (Point 10 6) a = evalFrom someTriangle $ pb . x get -- a == 0

note that:

evalFrom someTriangle (pb . x get) == someTriangle `fetch` (pb . x)

The advantage over `fetch`

is that it allows you to specify a different final action besides `get`

like so:

evalFrom someTriangle $ pb . x (modifyAndGet (+1))

evalFromT :: Monad m => b -> StateT b m a -> m a Source

Monad transformer version of `evalFrom`

. Note that `evalFromT`

= `flip`

`evalStateT`

.

execIn :: a -> StateT a Identity b -> a Source

Runs a state monad action on a structure and returns the updated structure

Use it to update fields:

somePoint = Point 5 3 a = execIn somePoint $ x (put 1) -- a == Point 1 3

note that:

execIn somePoint (x (put 1)) == (somePoint `update` x) 1

The advantage over `update`

is that it allows you to specify a different final action besides `put`

like so:

a = execIn somePoint $ x (modifyAndGet (+1)) -- a = Point 6 3

execInT :: Monad m => b -> StateT b m a -> m b Source

Monad transformer version of `execIn`

. Note that `execIn`

= `flip`

`execStateT`

.

# Structure lenses

runSTLense :: (Traversable f, Traversable t) => (forall s. f (State a b -> s) -> t s) -> f a -> (t b, f a) Source

This function has the magical ability to convert a function that fetches elements from a structure, to a function that lets you modify the elements in the structure.
The catch is that the structure must be a member of `Traversable`

.

So say you have a function that gets the diagonal of a list of lists:

diagonal :: [[a]] -> [a]

we can make a function that increments the diagonal like so:

addOne :: State Int () addOne = modify (+1)

incrementDiagonal :: [[a]] -> [[a]] incrementDiagonal xss = snd $ runSTLense (fmap ($ addOne) . diagonal) xss

Of course there are some helper combinators to make this cleaner:

incrementDiagonal xss = (addOne `to` diagonal) `from` xss

`runSTLense`

takes a function, a traversable structure, and returns a pair of (collected values, updated structure)
For clarification:

specialFunction :: (Traversable f, Traversable t) => f (State a b -> s) -> t s (collectedValues, updatedStructure) = runSTLense specialFunction originalStructure collectedAlmostValues = specialFunction processedOriginalStructure

processedOriginalStructure has the same shape as originalStructure but every element has been replaced with a transformer function (State a b -> s). specialFunction needs to return the result of the application of the functions in processedOriginalStructure to a state monad. The state monad by definition will return a result and potentially update state. Getting state will get the value of the element in originalStructure. Updating state will update the value of the element in updatedStructure. The returned values are gathered in collectedValues.

to :: Functor f => a -> (c -> f (a -> b)) -> c -> f b Source

A helper combinator used for applying a monad to element collected by a fetching function.

For example:

everyOther :: [a] -> [a] everyOther [] = [] everyOther (x:[]) = [x] everyOther (x:y:xs) = x : everyOther xs

addOne :: State Int () addOne = modify (+1)

test :: [Int] test = (addOne `to` everyOther) `from` [1, 2, 9, 6, 7, 8, 4] -- test == [2, 2, 10, 6, 8, 8, 5]

which is the same as:

test = snd $ runSTLense (addOne `to` everyOther) [1, 2, 9, 6, 7, 8, 4]

which is the same as:

test = snd $ runSTLense (fmap ($ addOne) . everyOther) [1, 2, 9, 6, 7, 8, 4]

from :: (Traversable t, Traversable f) => (forall s. t (State a b -> s) -> f s) -> t a -> t a Source

Applies `runSTLense`

to a function and a structure and returns the `snd`

of the result.
See `to`

for example of use.

# Generic helper functions

getAndModify :: MonadState s m => (s -> s) -> m s Source

Modifies the state in a state monad and returns the original value.

`getAndModify`

and `modifyAndGet`

should really be in `Class`

modifyAndGet :: MonadState s m => (s -> s) -> m s Source

Modifies the state in a state monad and returns the new value.

($=) :: MonadState s m => (m () -> b) -> s -> b infixl 0 Source

An operator for assigning a value to the value referenced by a lense. (see the example near the end of the tutorial at the start of this module)