diff options
Diffstat (limited to 'edit-lens')
-rw-r--r-- | edit-lens/ChangeLog.md | 5 | ||||
-rw-r--r-- | edit-lens/LICENSE | 30 | ||||
-rw-r--r-- | edit-lens/Setup.hs | 2 | ||||
-rw-r--r-- | edit-lens/edit-lens.cabal | 26 | ||||
-rw-r--r-- | edit-lens/src/Control/Lens/Edit.lhs | 158 |
5 files changed, 221 insertions, 0 deletions
diff --git a/edit-lens/ChangeLog.md b/edit-lens/ChangeLog.md new file mode 100644 index 0000000..8bae309 --- /dev/null +++ b/edit-lens/ChangeLog.md | |||
@@ -0,0 +1,5 @@ | |||
1 | # Revision history for edit-lens | ||
2 | |||
3 | ## 0.0.0.0 | ||
4 | |||
5 | * First version. | ||
diff --git a/edit-lens/LICENSE b/edit-lens/LICENSE new file mode 100644 index 0000000..4522849 --- /dev/null +++ b/edit-lens/LICENSE | |||
@@ -0,0 +1,30 @@ | |||
1 | Copyright (c) 2017, Gregor Kleen | ||
2 | |||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | * Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | * Redistributions in binary form must reproduce the above | ||
12 | copyright notice, this list of conditions and the following | ||
13 | disclaimer in the documentation and/or other materials provided | ||
14 | with the distribution. | ||
15 | |||
16 | * Neither the name of Gregor Kleen nor the names of other | ||
17 | contributors may be used to endorse or promote products derived | ||
18 | from this software without specific prior written permission. | ||
19 | |||
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
diff --git a/edit-lens/Setup.hs b/edit-lens/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/edit-lens/Setup.hs | |||
@@ -0,0 +1,2 @@ | |||
1 | import Distribution.Simple | ||
2 | main = defaultMain | ||
diff --git a/edit-lens/edit-lens.cabal b/edit-lens/edit-lens.cabal new file mode 100644 index 0000000..72c08c7 --- /dev/null +++ b/edit-lens/edit-lens.cabal | |||
@@ -0,0 +1,26 @@ | |||
1 | -- Initial edit-lens.cabal generated by cabal init. For further | ||
2 | -- documentation, see http://haskell.org/cabal/users-guide/ | ||
3 | |||
4 | name: edit-lens | ||
5 | version: 0.0.0.0 | ||
6 | -- synopsis: | ||
7 | -- description: | ||
8 | license: BSD3 | ||
9 | license-file: LICENSE | ||
10 | author: Gregor Kleen | ||
11 | maintainer: aethoago@141.li | ||
12 | -- copyright: | ||
13 | category: Control | ||
14 | build-type: Simple | ||
15 | extra-source-files: ChangeLog.md | ||
16 | cabal-version: >=1.10 | ||
17 | |||
18 | library | ||
19 | exposed-modules: Control.Lens.Edit | ||
20 | -- other-modules: | ||
21 | -- other-extensions: | ||
22 | build-depends: base >=4.9 && <4.10 | ||
23 | , lens | ||
24 | , data-default | ||
25 | hs-source-dirs: src | ||
26 | default-language: Haskell2010 | ||
diff --git a/edit-lens/src/Control/Lens/Edit.lhs b/edit-lens/src/Control/Lens/Edit.lhs new file mode 100644 index 0000000..69a6f7f --- /dev/null +++ b/edit-lens/src/Control/Lens/Edit.lhs | |||
@@ -0,0 +1,158 @@ | |||
1 | Ziel ist es zunächst edit-lenses alá \cite{hofmann2012edit} in Haskell zur Verfügung zu stellen. | ||
2 | Dabei werden wir sowohl die Definitionen aus \cite{hofmann2012edit} sowohl in natürlicher Sprache als auch in lauffähigem Haskell vorstellen: | ||
3 | |||
4 | \begin{code} | ||
5 | {-# LANGUAGE TypeFamilies | ||
6 | , KindSignatures | ||
7 | , FlexibleContexts | ||
8 | , FlexibleInstances | ||
9 | , MultiParamTypeClasses | ||
10 | , FunctionalDependencies | ||
11 | , AllowAmbiguousTypes | ||
12 | , GADTs | ||
13 | #-} | ||
14 | |||
15 | module Control.Lens.Edit | ||
16 | ( Module(..) | ||
17 | , StateMonoidHom | ||
18 | , HasEditLens(..) | ||
19 | , EditLens(..) | ||
20 | ) where | ||
21 | \end{code} | ||
22 | |||
23 | \begin{defn}[Moduln] | ||
24 | Ein Modul $M$ ist eine \emph{partielle Monoidwirkung} zusammen mit einem initialen Element (bzgl. der Monoidwirkung) auf dem Träger, d.h. $M = (\Dom M, \partial M, \init_M)$ ist ein Tupel aus einer Trägermenge $\Dom M$, einem Monoid $\partial M$ zusammen mit mit einer partiellen Funktion $\cdot \colon \Dom M \times \partial M \to \Dom$, die \emph{kompatibel} ist mit der Monoid-Struktur: | ||
25 | |||
26 | \begin{itemize} | ||
27 | \item $\forall m \in \Dom M \colon m \cdot 1_{\partial M} = m$ | ||
28 | \item $\forall m \in \Dom M, (e, e^\prime) \in (\partial M)^2 \colon m \cdot (e e^\prime) = (m \cdot e) \cdot e^\prime$ | ||
29 | \end{itemize} | ||
30 | |||
31 | und einem Element $\init_M \in \Dom M$, sodass gilt: | ||
32 | |||
33 | $$ \forall m \in \Dom M \ \exists \partial m \in \partial M \colon m = \init_M \cdot m^\prime $$ | ||
34 | |||
35 | Wir führen außerdem eine Abbildung $(\init_M \cdot)^{-1} \colon \Dom M \to \partial m$ ein, die ein $m$ auf ein arbiträr gewähltes $\partial m$ abbildet für das $\init_M \cdot \partial m = m$ gilt. | ||
36 | |||
37 | In Haskell charakterisieren wir Moduln über ihren Monoid, d.h. die Wahl des Monoiden \texttt{m} legt den Träger \texttt{Domain m}, die Wirkung \texttt{apply}, das initiale Element \texttt{init} und $(\init_M \cdot)^{-1}$ eindeutig fest\footnote{Betrachten wir mehrere Moduln über dem selben Träger (oder mit verschiedenen Wirkungen) führen wir neue, isomorphe, Typen ein (\texttt{newtype}-Wrappern)}. | ||
38 | Eine Repräsentierung als Typklasse bietet sich an: | ||
39 | |||
40 | \begin{code} | ||
41 | class Monoid m => Module m where | ||
42 | type Domain m :: * | ||
43 | apply :: Domain m -> m -> Maybe (Domain m) | ||
44 | -- ^ A partial monoid-action of `m` on `Domain m` | ||
45 | -- | ||
46 | -- prop> m `apply` mempty = m | ||
47 | -- prop> m `apply` (e `mappend` e') = (m `apply` e) `apply` e' | ||
48 | init :: Domain m | ||
49 | -- ^ 'init @m' (TypeApplication) is the initial element of 'm' | ||
50 | divInit :: Domain m -> Del m | ||
51 | -- ^ Calculate a representation of an element of 'Domain m' in 'Del m' | ||
52 | -- | ||
53 | -- prop> init `apply` divInit m = m | ||
54 | \end{code} | ||
55 | \end{defn} | ||
56 | |||
57 | Wir weichen von der originalen Definition von Moduln aus \cite{hofmann2012edit} darin ab, dass wir für das ausgezeichnete Element $\init_X$ des Trägers explizit (und konstruktiv) fordern, dass es ein initiales Element bzgl. der Monoidwirkung sei. | ||
58 | |||
59 | \begin{comment} | ||
60 | \begin{defn}[Modulhomomorphismen] | ||
61 | Unter einem Modulhomomorphismus zwischen Moduln $M$ und $M^\prime$ verstehen wir ein Paar $(f, \phi$) bestehend aus Abbildungen $f \colon \Dom M \to \Dom M^\prime$ und $\phi \colon \partial M \to \partial M^\prime$, sodass gilt: | ||
62 | \begin{itemize} | ||
63 | \item $\phi$ ist ein Monoidhomomorphismus: | ||
64 | |||
65 | \begin{itemize} | ||
66 | \item $\phi(1_{\partial M}) = 1_{\partial M^\prime}$ | ||
67 | \item $\forall (e, e^\prime) \in (\partial M)^2 \colon \phi(e e^\prime) = \phi(e) \phi(e^\prime)$ | ||
68 | \end{itemize} | ||
69 | \item $f$ erhält das initiale Element: | ||
70 | |||
71 | $$f(\init_M) = \init_N$$ | ||
72 | \item $f$ und $\phi$ sind \emph{kompatibel}: | ||
73 | |||
74 | $$\forall m \in \Dom M, e \in \partial M \colon f(m \cdot e) = f(m) \cdot \phi(e)$$ | ||
75 | \end{itemize} | ||
76 | |||
77 | \begin{code} | ||
78 | {- | ||
79 | data ModuleHom m n where | ||
80 | ModuleHom :: (Module m, Module n) => (Domain m -> Domain n) -> (m -> n) -> ModuleHom m n | ||
81 | -} | ||
82 | \end{code} | ||
83 | \end{defn} | ||
84 | \end{comment} | ||
85 | |||
86 | \begin{defn}[Zustandsbehaftete Monoidhomomorphismen] | ||
87 | Mit einer Menge von Komplementen $C$ und Monoiden $M$ und $N$ nennen wir eine partielle Funktion $\psi \colon C \times M \to C \times N$ einen zustandsbehafteten Monoidhomomorphismus wenn sie den folgenden Ansprüchen genügt: | ||
88 | |||
89 | \begin{itemize} | ||
90 | \item $\forall c \in C \colon \psi(1_M, c) = (1_N, c)$ | ||
91 | \item Mit $\psi(m, c) = (n, c^\prime)$ und $\psi(m^\prime, c^\prime) = (n^\prime, c^{\prime \prime})$: | ||
92 | |||
93 | $$\psi(m m^\prime, c) = (n n^\prime, c^{\prime \prime})$$ | ||
94 | \end{itemize} | ||
95 | |||
96 | \begin{code} | ||
97 | -- | A stateful monoid homomorphism | ||
98 | type StateMonoidHom s m n = (s, m) -> (s, n) | ||
99 | \end{code} | ||
100 | \end{defn} | ||
101 | |||
102 | \begin{defn}[edit-lenses] | ||
103 | Für Moduln $M$ und $N$ besteht eine symmetrische edit-lens zwischen $M$ und $N$ aus zwei zustandsbehafteten Monoidhomomorphismen $\Rrightarrow \colon C \times \partial M \to C \times \partial N$ und $\Lleftarrow \colon C \time \partial N \to C \times \partial M$, mit kompatiblem Komplement $C$, einem ausgezeichneten Element $\ground_C$ und einer \emph{Konsistenzrelation} $K \subset \Dom M \times C \times \Dom N$ sodass gilt: | ||
104 | |||
105 | \begin{itemize} | ||
106 | \item $(\init_M, \ground_C, \init_N) \in K$ | ||
107 | \item Für beliebige $m \in \Dom M, n \in \Dom n, \partial m \in \partial M, \partial n \in \partial N, c \in C$ folgt, wenn $m \cdot \partial m$ definiert ist und $\Rrightarrow(c, \partial m) = (c, \partial n)$ gilt: | ||
108 | |||
109 | \begin{itemize} | ||
110 | \item $n \cdot \partial n$ ist ebenfalls definiert | ||
111 | \item $(m \cdot \partial m, c^\prime, n \cdot \partial n) \in K$ | ||
112 | \end{itemize} | ||
113 | \item Analog für $\Lleftarrow$ | ||
114 | \end{itemize} | ||
115 | |||
116 | Wir schreiben auch nur \emph{edit-lens} für den symmetrischen Fall\footnote{Für den asymmetrischen Fall siehe \cite{johnson2016unifying}}. | ||
117 | |||
118 | In Haskell erwähnen wir die Konsistenzrelation nicht in der Erwartung, dass $\Rrightarrow$ und $\Lleftarrow$ nur auf konsistente Zustände angewandt werden (und somit auch entweder einen konsistenten Zustand erzeugen oder nichtt definiert sind): | ||
119 | |||
120 | \begin{code} | ||
121 | data EditLens c m n where | ||
122 | EditLens :: (Module m, Module n) => c -> StateMonoidHom c m n -> StateMonoidHom c n m -> EditLens c m n | ||
123 | |||
124 | class (Module m, Module n) => HasEditLens l m n | l -> m, l -> n where | ||
125 | type Complement l :: * | ||
126 | ground :: l -> Complement l | ||
127 | -- ^ A default state from 'Complement l' | ||
128 | propR :: l -> StateMonoidHom (Complement l) m n | ||
129 | -- ^ Map edits of 'm' to changes of 'n', maintaining some state from 'Complement l' | ||
130 | propL :: l -> StateMonoidHom (Complement l) n m | ||
131 | -- ^ Map edits of 'n' to changes of 'm', maintaining some state from 'Complement l' | ||
132 | |||
133 | -- | Inspect the components of an edit lens (e.g. 'EditLens') | ||
134 | instance HasEditLens (EditLens c m n) where | ||
135 | type Complement (EditLens c m n) = c | ||
136 | ground (EditLens g _ _) = g | ||
137 | propR (EditLens _ r _) = r | ||
138 | propL (EditLens _ _ l) = l | ||
139 | \end{code} | ||
140 | \end{defn} | ||
141 | |||
142 | \paragraph{Kompatibilität mit bestehenden lens frameworks} | ||
143 | |||
144 | Das einschlägige bestehende lens framework \cite{lens} konstruiert seine Linsen alá \citeauthor{laarhoven} wie folgt: | ||
145 | |||
146 | \begin{defn}[lenses alá \citeauthor{laarhoven}] | ||
147 | Für Typen $n$ und $m$ ist eine \emph{lens} $\ell$ von $n$ in $m$ eine Abbildung\footnote{Gdw. die betrachtete Linse einen Isomorphismus kodiert wird auch über den verwendeten Profunktor anstatt $\to$ quantifiziert} folgender Struktur: | ||
148 | |||
149 | $$ \forall f \, \text{Funktor} \colon \left ( \ell \colon \left ( m \to f(m) \right ) \to \left ( n \to f(n) \right ) \right )$$ | ||
150 | |||
151 | Durch geschickte Wahl des Funktors\footnote{\texttt{Const} bzw. \texttt{Identity}} $f$ können dann $\searrow \colon m \to n$ und $\nearrow \colon (m \to m) \to (n \to n)$ rekonstruiert werden oder verwandte Strukturen (folds, traversals, …) konstruiert werden. | ||
152 | \end{defn} | ||
153 | |||
154 | Es liegt nun nahe $\nearrow \colon (m \to m) \to (n \to n)$ mit $\Rrightarrow \colon \partial m \to \partial n$ zu identifizieren. | ||
155 | Und in der Tat, eine Funktion $\text{map} \colon (o \to o) \to \partial o$ für $o \in \{ m, n \}$ würde van Laarhoven-lenses in edit-lenses einbetten. | ||
156 | Die charakteristische Eigenschaft der Betrachtung als edit-lens, nämlich die algebraische Struktur von $\partial o$, würde hierbei jedoch notwendigerweise verloren gehen. | ||
157 | |||
158 | Wegen diesem Argument haben wir entschieden keine Komponierbarkeit (durch $\text{id} \colon a \to a$ und $\circ \colon (b \to c) \to (a \to b) \to (a \to c)$, wie in \cite{lens}) von edit-lenses mit van Laarhoven-lenses anzustreben. | ||