From 20edbe348d3460460ec22a9c0dce89e5d1db19b5 Mon Sep 17 00:00:00 2001 From: Matthias Fischmann Date: Tue, 29 Mar 2016 17:26:14 +0200 Subject: [PATCH 1/2] Add initial lens faq. --- docs/lens-faq.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 docs/lens-faq.md diff --git a/docs/lens-faq.md b/docs/lens-faq.md new file mode 100644 index 00000000..a734b540 --- /dev/null +++ b/docs/lens-faq.md @@ -0,0 +1,79 @@ +# The official Aula Lens FAQ + +This document is used to distribute knowledge of the lens library +within the aula dev team. It is hoped to be of wider usefulness, but +always rooted in aula-specific situations and examples. + +Questions are losely organized by the time they arise (youngest +first). + + +## What is the idea of "prismatic exception types"? + +Context: ?. + +... + + +## Lenses vs. Prisms vs. Traversals + +Context: PR#209. + +``` +data IdeaLocation = + IdeaLocationSpace { _ideaLocationSpace :: IdeaSpace } + | IdeaLocationTopic { _ideaLocationSpace :: IdeaSpace, _ideaLocationTopicId :: AUID Topic } + +makeLenses ''IdeaLocation +``` + +Following the docs of https://hackage.haskell.org/package/lens-4.13/docs/Control-Lens-TH.html#v:makeLenses we get a lens to access the idea space and only a traversal to access the topic id. + +``` +ideaLocationSpace :: Lens' IdeaLocation IdeaSpace +ideaLocationTopicId :: Traversal' IdeaLocation (AUID Topic) +``` + +My guess is that this type is impossible to fulfill. `ideaLocationTopicId` cannot be: + +* a getter, since there might be no `AUID Topic` +* a lens, since it cannot be a getter +* a prism, since we cannot reconstruct the `IdeaSpace` if we start only with an `AUID Topic` + +What we have from my previous comment is a `Traversal' IdeaLocation (AUID Topic)`. +Looking at the main diagram https://hackage.haskell.org/package/lens-4.13 a traversal is weaker than a lens or a prism. A traversal can be turned into a setter or a fold. Assume `t` to be a ++`Traversal' s a`: + +* `s ^.. t` get all the elements as a list: `[a]` +* `s ^? t` get the first element: `Maybe a` +* `s & t .~ a` set all the elements to `a`. +* `s & t %~ f` modify all the elements with `f`. + +Then `ideaTopicId` is the composition of `ideaLocation` (a lens) and `ideaLocationTopicId` (a traversal). However guessing the correct type signature can be difficult. My advice is to omit the type ++signatures at first. Since a traversal is weaker than a lens the resulting composite is a traversal. + +``` +ideaTopicId :: Traversal' Idea (AUID Topic) +ideaTopicId = ideaLocation . ideaLocationTopicId +``` + +What you were getting at with "is it somehow ok to yield a maybe here?" is that we know that there is either no topic id or a single topic id. The traversal is weaker it can be any number of them. ++A custom lens can be written as: + +``` +ideaLocationMaybeTopicId :: Lens' IdeaLocation (Maybe (AUID Topic)) +ideaLocationMaybeTopicId f = \case + IdeaLocationSpace spc -> mk spc <$> f Nothing + IdeaLocationTopic spc tid -> mk spc <$> f (Just tid) + where + mk spc = \case + Nothing -> IdeaLocationSpace spc + Just tid -> IdeaLocationTopic spc tid +``` + +The composite lens is then: + +``` +ideaMaybeTopicId :: Lens' Idea (Maybe (AUID Topic)) +ideaMaybeTopicId = ideaLocation . ideaLocationMaybeTopicId +``` From 3fcfb560302587b5d873d02b7fdbae44314d0dc3 Mon Sep 17 00:00:00 2001 From: Andor Penzes Date: Wed, 30 Mar 2016 15:52:35 +0200 Subject: [PATCH 2/2] Remove copy errors from lens-faq.md. --- docs/lens-faq.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/lens-faq.md b/docs/lens-faq.md index a734b540..6ed43a26 100644 --- a/docs/lens-faq.md +++ b/docs/lens-faq.md @@ -42,7 +42,7 @@ My guess is that this type is impossible to fulfill. `ideaLocationTopicId` canno What we have from my previous comment is a `Traversal' IdeaLocation (AUID Topic)`. Looking at the main diagram https://hackage.haskell.org/package/lens-4.13 a traversal is weaker than a lens or a prism. A traversal can be turned into a setter or a fold. Assume `t` to be a -+`Traversal' s a`: +`Traversal' s a`: * `s ^.. t` get all the elements as a list: `[a]` * `s ^? t` get the first element: `Maybe a` @@ -50,7 +50,7 @@ Looking at the main diagram https://hackage.haskell.org/package/lens-4.13 a trav * `s & t %~ f` modify all the elements with `f`. Then `ideaTopicId` is the composition of `ideaLocation` (a lens) and `ideaLocationTopicId` (a traversal). However guessing the correct type signature can be difficult. My advice is to omit the type -+signatures at first. Since a traversal is weaker than a lens the resulting composite is a traversal. +signatures at first. Since a traversal is weaker than a lens the resulting composite is a traversal. ``` ideaTopicId :: Traversal' Idea (AUID Topic) @@ -58,7 +58,7 @@ ideaTopicId = ideaLocation . ideaLocationTopicId ``` What you were getting at with "is it somehow ok to yield a maybe here?" is that we know that there is either no topic id or a single topic id. The traversal is weaker it can be any number of them. -+A custom lens can be written as: +A custom lens can be written as: ``` ideaLocationMaybeTopicId :: Lens' IdeaLocation (Maybe (AUID Topic))