summaryrefslogtreecommitdiff
path: root/edit-lens
diff options
context:
space:
mode:
Diffstat (limited to 'edit-lens')
-rw-r--r--edit-lens/ChangeLog.md5
-rw-r--r--edit-lens/LICENSE30
-rw-r--r--edit-lens/Setup.hs2
-rw-r--r--edit-lens/edit-lens.cabal26
-rw-r--r--edit-lens/src/Control/Lens/Edit.lhs158
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 @@
1Copyright (c) 2017, Gregor Kleen
2
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30OF 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 @@
1import Distribution.Simple
2main = 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
4name: edit-lens
5version: 0.0.0.0
6-- synopsis:
7-- description:
8license: BSD3
9license-file: LICENSE
10author: Gregor Kleen
11maintainer: aethoago@141.li
12-- copyright:
13category: Control
14build-type: Simple
15extra-source-files: ChangeLog.md
16cabal-version: >=1.10
17
18library
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 @@
1Ziel ist es zunächst edit-lenses alá \cite{hofmann2012edit} in Haskell zur Verfügung zu stellen.
2Dabei 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
15module Control.Lens.Edit
16 ( Module(..)
17 , StateMonoidHom
18 , HasEditLens(..)
19 , EditLens(..)
20 ) where
21\end{code}
22
23\begin{defn}[Moduln]
24Ein 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
31und 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
35Wir 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
37In 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)}.
38Eine Repräsentierung als Typklasse bietet sich an:
39
40\begin{code}
41class 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
57Wir 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]
61Unter 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{-
79data 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]
87Mit 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
98type StateMonoidHom s m n = (s, m) -> (s, n)
99\end{code}
100\end{defn}
101
102\begin{defn}[edit-lenses]
103Fü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
116Wir schreiben auch nur \emph{edit-lens} für den symmetrischen Fall\footnote{Für den asymmetrischen Fall siehe \cite{johnson2016unifying}}.
117
118In 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}
121data 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
124class (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')
134instance 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
144Das einschlägige bestehende lens framework \cite{lens} konstruiert seine Linsen alá \citeauthor{laarhoven} wie folgt:
145
146\begin{defn}[lenses alá \citeauthor{laarhoven}]
147Fü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
151Durch 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
154Es liegt nun nahe $\nearrow \colon (m \to m) \to (n \to n)$ mit $\Rrightarrow \colon \partial m \to \partial n$ zu identifizieren.
155Und 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.
156Die charakteristische Eigenschaft der Betrachtung als edit-lens, nämlich die algebraische Struktur von $\partial o$, würde hierbei jedoch notwendigerweise verloren gehen.
157
158Wegen 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.