© Stefania Loredana Nita and Marius Mihailescu 2019
Stefania Loredana Nita and Marius MihailescuHaskell Quick Syntax Referencehttps://doi.org/10.1007/978-1-4842-4507-1_20

20. Lens

Stefania Loredana Nita1  and Marius Mihailescu1
(1)
Bucharest, Romania
 

In this chapter, you will learn about a particular type of functional reference. First, let’s see define functional reference: reference means you can access and/or modify part of the values, and functional means that the flexibility and composability of functions are assured while accessing these parts.

Lenses are a type of functional reference, implemented in Haskell by the lens library , that represent a first-class getter and setter. With a lens, you can do the following things:
  • Access a subpart

  • Alter the whole by modifying a subpart

  • Merge the lens with another lens to get a deeper view

When working with lenses, you need to follow some rules, depending on what you want to obtain.
  • Get-put : If something is modified by changing just the subpart, then nothing happens.

  • Put-get : When a particular subpart is inserted and you want to check the whole result, you will get exactly that subpart.

  • Put-put : If subpart a is inserted, then a is modified by inserting subpart b, and this is actually the same as just inserting b.

If these rules sound a bit odd, follow this chapter and things will become clearer.

The most commonly used types of lenses are as follows:
  • Lens's a: When type s always contains type a, Lens s a is used to get or set the a inside of s. This is characterized as a has-a relationship.

  • Prism's a: When type s could contain type a, Prism s a is used to extract a if it exists; also, given the a, it may create the s. This is characterized as an is-a relationship.

  • Traversal's a : This finds as many a’s as can be contained in s.

  • Iso's a : This shows that s and a are representations of the same type.

In the previous list, the ' mark means that the lens is a simpler version of the main lens.

Let’s see some simple examples of using lenses. To use them, you need to install the lens package. As usual, open a terminal and type the following :
cabal install lens
Then, in GHCi, import the library.
Prelude> import Control.Lens
The first examples are focused on tuples. The lens _1 concentrates the attention on the first element of a tuple. Some functions that can be used with _1 are view, over, and set.
Prelude Control.Lens> view _1 ("goal", "chaff") "goal"
Prelude Control.Lens> view _1 ("Haskell", "Lens") "Haskell"
Prelude Control.Lens> over _1 (++ " programming") ("Haskell", "Lens")
("Haskell programming","Lens")
Prelude Control.Lens> set _1 "Functional References" ("Haskell", "Lens")
("Functional References","Lens")

These examples are self-explanatory. Maybe over is a little more complex: the alteration is applied on the focal point _1. The three functions have an infix form: view as (^.), set as (.~), over as (%~).

The mathematical operators can be applied as lenses, in the following forms: (+~), (-~), (*~), (<>~).

By now, all these functions belong to Lens. Let’s continue with Prism. The main functions in Prism are preview (^?), which can get a value from a structure, and review (#), which constructs s from a.
Prelude Control.Lens> preview _Left (Left "Haskell")
Just "Haskell"
Prelude Control.Lens> review _Left "Hakell"
Left "Hakell"
Prelude Control.Lens> review _Just "Hakell"
Just "Hakell"
Prelude Control.Lens> preview _Cons [1,2,3]
Just (1,[2,3])
Some useful functions in Traversal are traverse , which is a generalization of over, and toListOf (^..), which creates a list from what it traverses.
Prelude Control.Lens> (_1 . traverse) (x -> [x, -x]) ([11,12], "Haskell")
[([11,12],"Haskell"),([11,-12],"Haskell"),([-11,12],"Haskell"),([-11,-12],"Haskell")]
Prelude Control.Lens> toListOf _2 (4, [1,2,3])
[[1,2,3]]
Prelude Control.Lens> toListOf _1 (4, [1,2,3])
[4]
Let’s see a simple example of using traversals, from a great post of Chris Penner.1 First, define a data structure like this:
data Transaction =
    Withdrawal {amount :: Int}
    | Deposit {amount :: Int }
  deriving Show
This representation is for a bank transaction, where you have the two constructors Withdrawal and Deposit, each of them with an amount value that gets the sum from either of the constructors. With a list of transactions, to focus on every element of the list using a traversal, proceed like this:
simpleTransactions :: Traversal' [Transaction] Transaction
simpleTransactions = traverse

Note that simpleTransactions has the same signature as traverse . The previous function can be successfully replaced by traverse. Moreover, it is actually recommended to use traverse instead to define your own versions.

In fact, simpleTransactions won’t work. Traversal' s a may not change the structure’s type or the focused value, which means with simpleTransactions , Transaction may not be changed in other type. Let’s check it out with this example:
Prelude Control.Lens> :{
Prelude Control.Lens| someTransactions :: [Transaction]
Prelude Control.Lens| someTransactions = [Deposit 100, Withdrawal 50]
Prelude Control.Lens| :}
Prelude Control.Lens> someTransactions & simpleTransactions .~ "a string"
error:
    • Couldn't match expected type 'Transaction'
                  with actual type '[Char]'
    • In the second argument of '(.~)', namely '"a string"'
      In the second argument of '(&)', namely
        'simpleTransactions .~ "a string"'
      In the expression:
        someTransactions & simpleTransactions .~ "a string"
The & used in lenses is defined as a flip, so it will reverse the application operator. If the traversal is allowed to change the type of the focus, it will work.
typeChangingTransactions :: Traversal [Transaction] [result] Transaction result
typeChangingTransactions = traverse
Then you have this:
Prelude Control.Lens > someTransactions & typeChangingTransactions .~ "a string"
["a string","a string"]
Going further with lenses, let’s focus now on Iso, whose name comes from isomorphism . This means it represents a connection between equivalent types. The following is an example of Iso:
isoExample :: Iso' (Maybe a) (Either () a)
Prelude Control.Lens> Just "hello" ^. isoExample
Right "hello"
Iso has an interesting behavior because it is invertible and always succeeds, and by making some changes, you can easily get the other types of lenses. Giving up invertibility, you get a Lens; giving up successfulness you get a Prism; and giving up both, you get almost a Traversal. To actually get a Traversal , you need to go a step further and renounce having at most one target. Speaking more technically, note the following:
  • The existence of i :: Iso's a says that having the value s, you also have the value a and the inverse. Based on this, the important functions in Iso are view i :: s -> a and review i :: a -> s. Both of them succeed and have no loss.

  • The existence of l :: Lens's a says that having the value s, you have also the value a, but the inverse way is not possible. It is possible that the function view l :: s -> a can eliminate some information in its way, because it is not guaranteed that a conversion is lossless. So, having the a, you can’t go backward to s.

  • Finally, the existence of p :: Prism's a says that having the value s, it is possible to also have the value a, but this fact is not guaranteed. Even when converting with preview p :: s -> Maybe a is possible to fail, you still have the inverse of review p :: a -> s.

Summary

In this chapter, you learned the following:
  • What lenses are

  • When lenses can be used and which are the main functions for every type of lens

  • How you can obtain the other lenses from Iso

Note that lenses are analogous to structures in other programming languages, such as C.

References

  1. 1.

    S. Fischer, H. Zhenjiang, and H. Pacheco, “A Clear Picture of Lens Laws,” International Conference on Mathematics of Program Construction (Springer, 2015)

     
  2. 2.

    R. O’Connor, “Functor Is to Lens as Applicative Is to Biplate: Introducing Multiplate,” arXiv preprint arXiv:1103.2841 (2011)

     
  3. 3.

    Lens: lenses, folds and traversals, http://hackage.haskell.org/package/lens

     
  4. 4.
     
  5. 5.
     
  6. 6.
     
  7. 7.
     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.20.224.107