[more updates to IxSetDataLens Jeremy Shaw **20120122014851 Ignore-this: 5aa7ef9b59abc1f2c3be0f0da34650db ] hunk ./IxSetDataLens.markdown.lhs 1 - hunk ./IxSetDataLens.markdown.lhs 13 +It can take a bit of practice to get used to lenses. But, fortunately, using them is completely optional -- so if they are not your thing, you don't have to use them. In this tutorial we will start with a general tutorial on using lenses, and then finish up with showing how to use them with `IxSet` and `acid-state`. + hunk ./IxSetDataLens.markdown.lhs 21 +> import Control.Category ((.), (>>>)) hunk ./IxSetDataLens.markdown.lhs 30 -> +> import Prelude hiding ((.)) hunk ./IxSetDataLens.markdown.lhs 114 -#ifdef HsColour -> stepcutFirstName' :: Text -> stepcutFirstName' = _firstName $ _name $ stepcut -#endif + +> stepcutFirstName2 :: Text +> stepcutFirstName2 = _firstName $ _name $ stepcut + hunk ./IxSetDataLens.markdown.lhs 134 -> stepcutFirstName'' :: Text -> stepcutFirstName'' = (stepcut ^. name) ^. firstName +> stepcutFirstName3 :: Text +> stepcutFirstName3 = (stepcut ^. name) ^. firstName hunk ./IxSetDataLens.markdown.lhs 147 +

Lens is an instance of Category

+ +`Lens` is an instance of `Category`. That means we can use the `.` operator from `Category` to compose lenses. + +The normal `.` looks like this: + +
+#ifdef HsColour +-- | as defined in 'Prelude' +(.) :: (b -> c) -> (a -> b) -> a -> c +#endif +
+ +But `.` can be generalized to work for any `Category` like this: + +
+#ifdef HsColour +-- | as defined in 'Control.Category' +(.) :: (Category cat) => cat b c -> cat a b -> cat a c +#endif +
+ +If you look closely at the imports at the top, you will notice that we hide `.` from the `Prelude` and imported the version from `Control.Category` instead. Now we can write this: + +
+ +> stepcutFirstName4 :: Text +> stepcutFirstName4 = firstName . name ^$ stepcut + +
+ +Which looks very similar to the non-lens version: + +
+ +> stepcutFirstName5 :: Text +> stepcutFirstName5 = _firstName . _name $ stepcut + +
+ hunk ./IxSetDataLens.markdown.lhs 197 -Once again we have a lazier version `^=` and a stricter vesrion `^!=`. +Once again we have a lazier version `^=` and a stricter version `^!=`. hunk ./IxSetDataLens.markdown.lhs 251 +Another option would be to leverage the `Category` instance and use the `.` operator: + +
+ +> setNick2 :: Text -> (User -> User) +> setNick2 newNick = (nickName . name) ^= newNick + +
+ +However, I find that a bit confusing to read, because the field names are listed right-to-left, but the overall flow of that line is left-to-right. If we want a consistent left-to-right feel we can use the `>>>` operator: + +
+#ifdef HsColour +> (>>>) :: Control.Category.Category cat => cat a b -> cat b c -> cat a c +#endif +
+ +
+ +> setNick3 :: Text -> (User -> User) +> setNick3 newNick = (name >>> nickName) ^= newNick + +
hunk ./IxSetDataLens.markdown.lhs 362 +We can also try to use `>>>` instead of all those `^%=`, but the `fmap` is a bit troublesome: + +
+ +> changeNick2 :: UserState +> changeNick2 = ((users >>> user (UserId 0)) ^%= fmap ((name >>> nickName) ^= "stepkut")) userState + +
+ +Additionally, it seems like `^%=` binds to tightly and so we need some extra `( )` to keep things happy. + hunk ./IxSetDataLens.markdown.lhs 407 + +`data-lens-fd` provides a few other functions that you can use to get, set, and modify the state in an `Update` or `Query` event. Check out the haddock documentation for data-lens-fd. + +