The app-lens package

[maintain]

A bidirectional transformation connects data in difference formats, maintaining consistency amid separate updates. The lens programming language---with Kmett's Haskell lens package being one of the most influentials---is a solution to this problem.

Many lens implementations (including Kmett's Haskell library) only support the point-free style of programming. Though concise at times, this style becomes less handy when programs get more complicated.

This module provides the infrastructure for programming complex bidirectional transformations, by representing lenses as functions that are subject to the normal applicative-style programming. For example, let us consider the unlines functions and to define a lens version of it. In our framework we can program through pattern matching and explicit recursion as in normal functional programming.

 unlinesF :: [L s String] -> L s String
 unlinesF []     = new ""
 unlinesF (x:xs) = catLineF x (unlinesF xs)
    where catLineF = lift2 catLineL

Here, lift2 :: Lens' (a,b) c -> (forall s. L s a -> L s b -> L s c) and new :: a -> (forall s. L s a) lift lenses to functions. The former is for binary lenses and the latter is for constant lenses. We can then apply lenses as functions, alleviating the need of specialized combinators. In the above, we omitted the definition of a primitive lens catLineL :: Lens' (String, String) String that concatenates two strings with a newline in between.

Simply unlifting (unlift, unlift2, unliftT) such lens functions gives us the desired lenses.

 unlinesL :: Lens' [String] String
 unlinesL = unliftT unlinesF

The obtained lens works as expected.

 >>> ["banana", "orange", "apple"] ^. unlinesL
 "banana\norange\napple\n"
 >>> ["banana", "orange", "apple"] & unlinesL .~ "Banana\nOrange\nApple\n"
 ["Banana","Orange","Apple"]

One may prefer to define unlinesF with foldr. Indeed, we can use foldr as below because catLineF and unlinesF are simply Haskell functions.

 unlinesF = foldr (lift2 catLineL) (new "")

Here, the program is written in a point-free manner similar to that of the other lens frameworks. But note that this foldr is just Haskell's foldr, instead of a special combinator for lenses.

More examples can be found at "Examples" in the source code https://bitbucket.org/kztk/app-lens/downloads.

Remark. The applicative-style programming is possible in our implementation because a function representation different from Kmett's is used for lenses. As a result, when we program record-field access chains such as

 src .^ l1 . l2
 src & l1 . l2 .~ tgt'

The order of composition is inverted in our implementation.

 src .^ unlift (lift l2 . lift l1)
 src & unlift (lift l2 . lift l1) .~ tgt'

This difference causes slight inconvenience for record updates, but is crucial in allowing the applicative-style lens programming we aim for.

Properties

Versions0.1.0.0, 0.1.0.1, 0.1.0.1, 0.1.0.3
Dependenciesbase (>=4.7 && <4.9), containers (==0.5.*), lens (>=4 && <4.13), mtl (>=2.2 && <2.4) [details]
LicenseBSD3
Copyright(c) Kazutaka Matsuda, 2015
AuthorKazutaka Matsuda
Maintainerkztk@ecei.tohoku.ac.jp
CategoryData, Lenses
Home pagehttps://bitbucket.org/kztk/app-lens
Bug trackerhttps://bitbucket.org/kztk/app-lens/issues
Source repositoryhead: git clone https://bitbucket.org/kztk/app-lens
UploadedThu Sep 3 05:18:10 UTC 2015 by kztk

Modules

[Index]

Flags

NameDescriptionDefaultType
usevanlaarhovenUse Control.Lens.Lens' as internal representations. (1.5 times speed up for 'lift' but 1000 times slow down for 'lift2')DisabledAutomatic

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainers' corner

For package maintainers and hackage trustees