summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorEdward Z. Yang <ezyang@cs.stanford.edu>2014-07-22 15:55:59 +0100
committerEdward Z. Yang <ezyang@cs.stanford.edu>2014-07-22 15:55:59 +0100
commit1db9983c76c5f5ec8a162de56a69136e2e582eb3 (patch)
treed0e8298e495fe269b02ed5bb17dfe3cfd29f4bea /docs
parentb709f0a047dc036de15dc43d3b0ab88d3e32c5e6 (diff)
downloadhaskell-1db9983c76c5f5ec8a162de56a69136e2e582eb3.tar.gz
Rewrite package/module identity section
Signed-off-by: Edward Z. Yang <ezyang@cs.stanford.edu>
Diffstat (limited to 'docs')
-rw-r--r--docs/backpack/backpack-impl.tex469
1 files changed, 314 insertions, 155 deletions
diff --git a/docs/backpack/backpack-impl.tex b/docs/backpack/backpack-impl.tex
index b0b43ba87a..bcb6447f56 100644
--- a/docs/backpack/backpack-impl.tex
+++ b/docs/backpack/backpack-impl.tex
@@ -1,5 +1,6 @@
\documentclass{article}
+\usepackage{pifont}
\usepackage{graphicx} %[pdftex] OR [dvips]
\usepackage{fullpage}
\usepackage{wrapfig}
@@ -8,6 +9,8 @@
\usepackage{hyperref}
\usepackage{tikz}
\usepackage{color}
+\usepackage{footnote}
+\usepackage{float}
\usetikzlibrary{arrows}
\usetikzlibrary{positioning}
\setlength{\droptitle}{-6em}
@@ -250,21 +253,297 @@ A \emph{non-goal} is to allow users to upgrade upstream libraries
without recompiling downstream. This is an ABI concern and we're not
going to worry about it.
-\section{Module identities}
+\clearpage
+
+\section{Module and package identity}
+
+\begin{figure}[H]
+\begin{tabular}{p{0.45\textwidth} p{0.45\textwidth}}
+\begin{verbatim}
+package p where
+ A :: [ data X ]
+ P = [ import A; data Y = Y X ]
+package q where
+ A1 = [ data X = X1 ]
+ A2 = [ data X = X2 ]
+ include p (A as A1, P as P1)
+ include p (A as A2, P as P2)
+\end{verbatim}
+&
+\begin{verbatim}
+package p where
+ A :: [ data X ]
+ P = [ data T = T ] -- no A import!
+package q where
+ A1 = [ data X = X1 ]
+ A2 = [ data X = X2 ]
+ include p (A as A1, P as P1)
+ include p (A as A2, P as P2)
+\end{verbatim}
+\\
+(a) Type equality must consider holes\ldots &
+(b) \ldots but how do we track dependencies? \\
+\end{tabular}
+\caption{Two similar examples}\label{fig:simple-ex}
+\end{figure}
+
+One of the central questions one encounters when type checking Haskell
+code is: \emph{when are two types equal}? In ordinary Haskell, the
+answer is simple: ``They are equal if their \emph{original names} (i.e.,
+where they were originally defined) are the same.'' However, in
+Backpack, the situation is murkier due to the presence of \emph{holes}.
+Consider the pair of examples in Figure~\ref{fig:simple-ex}.
+In Figure~\ref{fig:simple-ex}a, the types \m{B1}.\verb|Y| and \m{B2}.\verb|Y| should not be
+considered equal, even though na\"\i vely their original names are
+\pname{p}:\m{B}.\verb|Y|, since their arguments are different \verb|X|'s!
+On the other hand, if we instantiated \pname{p} twice with the same \m{A}
+(e.g., change the second include to \texttt{include p (A as A1, P as P2)}),
+we might consider the two resulting \verb|Y|'s
+equal, an \emph{applicative} semantics of identity instantiation. In
+Figure~\ref{fig:simple-ex}b, we see that even though \m{A} was instantiated differently,
+we might reasonably wonder if \texttt{T} should still be considered the same,
+since it has no dependence on the actual choice of \m{A}.
+
+In fact, there are quite a few different choices that can be made here.
+Figures~\ref{fig:applicativity}~and~\ref{fig:granularity} summarize the various
+choices on two axes: the granularity of applicativity (under what circumstances
+do we consider two types equal) and the granularity of dependency (what circumstances
+do we consider two types not equal)? A \ding{52} means the design we have chosen
+answers the question affirmatively---\ding{54}, negatively---but all of these choices
+are valid points on the design space.
+
+\subsection{The granularity of applicativity}
+
+An applicative semantics of package instantiation states that if a package is
+instantiated with the ``same arguments'', then the resulting entities it defines
+should also be considered equal. Because Backpack uses \emph{mix-in modules},
+it is very natural to consider the arguments of a package instantiation as the
+modules, as shown in Figure~\ref{fig:applicativity}b: the same module \m{A} is
+linked for both instantiations, so \m{P1} and \m{P2} are considered equal.
+
+However, we consider the situation at a finer granularity, we might say, ``Well,
+for a declaration \texttt{data Y = Y X}, only the definition of type \verb|X| matters.
+If they are the same, then \verb|Y| is the same.'' In that case, we might accept
+that in Figure~\ref{fig:applicativity}a, even though \pname{p} is instantiated
+with different modules, at the end of the day, the important component \verb|X| is
+the same in both cases, so \verb|Y| should also be the same. This is a sort of
+``extreme'' view of modular development, where every declaration is desugared
+into a separate module. In our design, we will be a bit more conservative, and
+continue with module level applicativity, in the same manner as Paper Backpack.
+
+\paragraph{Implementation considerations}
+Compiling Figure~\ref{fig:applicativity}b to dynamic libraries poses an
+interesting challenge, if every package compiles to a dynamic library.
+When we compile package \pname{q}, the libraries we end up producing are \pname{q}
+and an instance of \pname{p} (instantiated with \pname{q}:\m{A}). Furthermore,
+\pname{q} refers to code in \pname{p} (the import in \m{Q}), and vice versa (the usage
+of the instantiated hole \m{A}). When building static libraries, this circular
+dependency doesn't matter: when we link the executable, we can resolve all
+of the symbols in one go. However, when the libraries in question are
+dynamic libraries \verb|libHSq.so| and \verb|libHSp(q:A).so|, we now have
+a \emph{circular dependency} between the two dynamic libraries, and most dynamic
+linkers will not be able to load either of these libraries.
+
+To break the circularity in Figure~\ref{fig:applicativity}b, we have to \emph{inline}
+the entire module \m{A} into the instance of \pname{p}. Since the code is exactly
+the same, we can still consider the instance of \m{A} in \pname{q} and in \pname{p}
+type equal. However, in Figure~\ref{fig:applicativity}c, applicativity has been
+done at a coarser level: although we are using Backpack's module mixin syntax,
+morally, this example is filling in the holes with the \emph{package} \pname{a}
+(rather than a module). In this case, we can achieve code sharing, since
+\pname{p} can refer directly to \pname{a}, breaking the circularity.
+
+\newcolumntype{C}{>{\centering\arraybackslash}p{0.3\textwidth}}
+ \begin{savenotes}
+\begin{figure}
+ \begin{tabular}{C C C}
+\begin{verbatim}
+package q where
+ A = [ data X = X ]
+ A1 = [ import A; x = 0 ]
+ A2 = [ import A; x = 1 ]
+ include p (A as A1, P as P1)
+ include p (A as A2, P as P2)
+ Q = [ import P1; ... ]
+\end{verbatim}
+&
+\begin{verbatim}
+package q where
+ A = [ data X = X ]
+
+
+ include p (A, P as P1)
+ include p (A, P as P2)
+ Q = [ import P1; ... ]
+\end{verbatim}
+&
+\begin{verbatim}
+package a where
+ A = [ data X = X ]
+package q where
+ include a
+ include p (A, P as P1)
+ include p (A, P as P2)
+ Q = [ import P1; ... ]
+\end{verbatim}
+ \\
+ (a) Declaration applicativity \ding{54} &
+ (b) Module applicativity \ding{52} &
+ (c) Package applicativity \ding{52} \\
+\end{tabular}
+\caption{Choices of granularity of applicativity on \pname{p}: given \texttt{data Y = Y X}, is \m{P1}.\texttt{Y} equal to \m{P2}.\texttt{Y}?}\label{fig:applicativity}
+\end{figure}
+\end{savenotes}
+
+\subsection{The granularity of dependency}
+
+\begin{savenotes}
+\newcolumntype{C}{>{\centering\arraybackslash}p{0.3\textwidth}}
+\begin{figure}
+ \begin{tabular}{C C C}
+\begin{verbatim}
+package p(A,P) where
+ A :: [ data X ]
+ P = [
+ import A
+ data T = T
+ data Y = Y X
+ ]
+\end{verbatim}
+&
+\begin{verbatim}
+package p(A,P) where
+ A :: [ data X ]
+ B = [ data T = T ]
+ C = [
+ import A
+ data Y = Y X
+ ]
+ P = [
+ import B
+ import C
+ ]
+\end{verbatim}
+&
+\begin{verbatim}
+package b where
+ B = [ data T = T ]
+package c where
+ A :: [ data X ]
+ C = [
+ import A
+ data Y = Y X
+ ]
+package p(A,P) where
+ include b; include c
+ P = [ import B; import C ]
+\end{verbatim}
+ \\
+ (a) Declaration granularity \ding{54} &
+ (b) Module granularity \ding{54} &
+ (c) Package granularity \ding{52} \\
+\end{tabular}
+\caption{Choices of granularity for dependency: is the identity of \texttt{T} independent of how \m{A} is instantiated?}\label{fig:granularity}
+\end{figure}
+
+\end{savenotes}
+
+In the previous section, we considered \emph{what} entities may be considered for
+computing dependency; in this section we consider \emph{which} entities are actually
+considered as part of the dependencies for the declaration/module/package we're writing.
+Figure~\ref{fig:granularity} contains a series of examples which exemplify the choice
+of whether or not to collect dependencies on a per-declaration, per-module or per-package basis:
+
+\begin{itemize}
+ \item Package-level granularity states that the modules in a package are
+considered to depend on \emph{all} of the holes in the package, even if
+the hole is never imported. Figure~\ref{fig:granularity}c is factored so that
+\verb|T| is defined in a distinct package \pname{b} with no holes, so no matter
+the choice of \m{A}, \m{B}.\verb|T| will be the same. On the other hand, in
+Figure~\ref{fig:granularity}b, there is a hole in the package defining \m{B},
+so the identity of \verb|T| will depend on the choice of \m{A}.
+
+\item Module-level granularity states that each module has its own dependency,
+computed by looking at its import statements. In this setting, \verb|T| in Figure~\ref{fig:granularity}b
+is independent of \m{A}, since the hole is never imported in \m{B}. But once again, in
+Figure~\ref{fig:granularity}a, there is an import in the module defining \verb|T|,
+so the identity of \verb|T| once again depends on the choice of \m{A}.
+
+\item Finally, at the finest level of granularity, one could chop up \pname{p} in
+Figure~\ref{fig:granularity}a, looking at the type declaration-level dependency
+to suss out whether or not \verb|T| depends on \m{A}. It doesn't refer to
+anything in \m{A}, so it is always considered the same.
+\end{itemize}
+
+It is well worth noting that the system described by Paper Backpack tracks dependencies per module;
+however, we have decided that we will implement tracking per package instead:
+a coarser grained granularity which accepts less programs.
+
+Is a finer form of granularity \emph{better?} Not necessarily! For
+one, we can always split packages into further subpackages (as was done
+in Figure~\ref{fig:granularity}c) which better reflect the internal hole
+dependencies, so it is always possible to rewrite a program to make it
+typecheck---just with more packages. Additionally, the finer the
+granularity of dependency, the more work I have to do to understand what
+the identities of entities in a module are. In Paper Backpack, I have
+to understand the imports of all modules in a package; with
+declaration-granularity, I have to understand the entire code. This is
+a lot of work for the developer to think about; a more granular model is
+easier to remember and reason about. Finally, package-level granularity
+is much easier to implement, as it preserves the previous compilation
+model, \emph{one library per package}. At a fine level of granularity, we
+may end up repeatedly compiling a module which actually should be considered
+``the same'' as any other instance of it.
+
+Nevertheless, finer granularity can be desirable from an end-user perspective.
+Usually, these circumstances arise when library-writers are forced to split their
+components into many separate packages, when they would much rather have written
+a single package. For example, if I define a data type in my library, and would
+like to define a \verb|Lens| instance for it, I would create a new package just
+for the instance, in order to avoid saddling users who aren't interested in lenses
+with an extra dependency. Another example is test suites, which have dependencies
+on various test frameworks that a user won't care about if they are not planning
+on testing the code. (Cabal has a special case for this, allowing the user
+to write effectively multiple packages in a single Cabal file.)
+
+
+\subsection{Cabal dependency resolution}
+
+Currently, when we compile a Cabal
+package, Cabal goes ahead and resolves \verb|build-depends| entries with actual
+implementations, which we compile against. A planned addition to the package key,
+independent of Backpack, is to record the transitive dependency tree selected
+during this dependency resolution process, so that we can install \pname{libfoo-1.0}
+twice compiled against different versions of its dependencies.
+What is the relationship to this transitive dependency tree of \emph{packages},
+with the subterms of our package identities which are \emph{modules}? Does one
+subsume the other? In fact, these are separate mechanisms---two levels of indirections,
+so to speak.
+
+To illustrate, suppose I write a Cabal file with \verb|build-depends: foobar|. A reasonable assumption is that this translates into a
+Backpack package which has \verb|include foobar|. However, this is not
+actually a Paper Backpack package: Cabal's dependency solver has to
+rewrite all of these package references into versioned references
+\verb|include foobar-0.1|. For example, this is a pre-package:
+
+\begin{verbatim}
+package foo where
+ include bar
+\end{verbatim}
+
+and this is a Paper Backpack package:
-We are going to implement module identities slightly differently from
-the way it was described from the Backpack paper. Motivated by
-implementation considerations, we coarsen the
-granularity of dependency tracking, so that it's not necessary to
-calculate the transitive dependencies of every module: we only do it per
-package. In this next section, we recapitulate Section 3.1 of the
-original Backpack paper, but with our new granularity. Comparisons to
-original Backpack will be recorded in footnotes. Then we more generally
-discuss the differing points of the design space these two occupy, and
-how this affects what programs typecheck and how things are actually
-implemented.
+\begin{verbatim}
+package foo-0.3[bar-0.1[baz-0.2]] where
+ include bar-0.1[baz-0.2]
+\end{verbatim}
-\subsection{The new scheme}
+This tree is very similar to the one tracking dependencies for holes,
+but we must record this tree \emph{even} when our package has no holes.
+% As a final example, the full module
+% identity of \m{B1} in Figure~\ref{fig:granularity} may actually be $\pname{p-0.9(q-1.0[p-0.9]:A1)}$:\m{B}.
+
+\subsection{The new scheme, formally}
\begin{wrapfigure}{R}{0.5\textwidth}
\begin{myfig}
@@ -273,10 +552,10 @@ implemented.
\text{Package Names (\texttt{PkgName})} & P &\in& \mathit{PkgNames} \\
\text{Module Path Names (\texttt{ModName})} & p &\in& \mathit{ModPaths} \\
\text{Module Identity Vars} & \alpha,\beta &\in& \mathit{IdentVars} \\
- \text{Package Key (\texttt{PackageId})} & \K &::=& P(\vec{p\mapsto\nu}) \\
+ \text{Package Key (\texttt{PackageKey})} & \K &::=& P(\vec{p\mapsto\nu}) \\
\text{Module Identities (\texttt{Module})} & \nu &::=&
\alpha ~|~
- \mu\alpha.\K\colon\! p \\
+ \K\colon\! p \\
\text{Module Identity Substs} & \phi,\theta &::=&
\{\vec{\alpha \coloneqq \nu}\} \\
\end{array}
@@ -286,16 +565,14 @@ implemented.
\end{myfig}
\end{wrapfigure}
+In this section, we give a formal treatment of our choice in the design space, in the
+same style as the Backpack paper, but omitting mutual recursion, as it follows straightforwardly.
Physical module
-identities $\nu$, referred to in GHC as \emph{original names}, are either (1) \emph{variables} $\alpha$, which are
-used to represent holes; (2) a concrete module $p$ defined in package
+identities $\nu$, the \texttt{Module} component of \emph{original names} in GHC, are either (1) \emph{variables} $\alpha$, which are
+used to represent holes\footnote{In practice, these will just be fresh paths in a special package key for variables.} or (2) a concrete module $p$ defined in package
$P$, with holes instantiated with other module identities (might be
empty)\footnote{In Paper Backpack, we would refer to just $P$:$p$ as the identity
-constructor. However, we've written the subterms specifically next to $P$ to highlight the semantic difference of these terms.}; or (3) \emph{recursive} module identities, defined via
-$\mu$-constructors.\footnote{Actually, all concrete modules implicitly
- define a $\mu$-constructor, and we plan on using de Bruijn indices
- instead of variables in this case, a locally nameless
-representation.}
+constructor. However, we've written the subterms specifically next to $P$ to highlight the semantic difference of these terms.}.
As in traditional Haskell, every package contains a number of module
files at some module path $p$; within a package these paths are
@@ -304,8 +581,7 @@ that they are immediately assigned to a module path $p$ which is incorporated
into their identity. A module identity $\nu$ simply augments this
with subterms $\vec{p\mapsto\nu}$ representing how \emph{all} holes in the package $P$
were instantiated.\footnote{In Paper Backpack, we do not distinguish between holes/non-holes, and we consider all imports of the \emph{module}, not the package.} This naming is stable because the current Backpack surface syntax does not allow a logical path in a package
-to be undefined. A package key is $P(\vec{p\mapsto\nu})$; it is the entity
-that today is internally referred to in GHC as \texttt{PackageId}.
+to be undefined. A package key is $P(\vec{p\mapsto\nu})$.
Here is the very first example from
Section 2 of the original Backpack paper, \pname{ab-1}:
@@ -320,7 +596,7 @@ Section 2 of the original Backpack paper, \pname{ab-1}:
The identities of \m{A} and \m{B} are
\pname{ab-1}:\mname{A} and \pname{ab-1}:\mname{B}, respectively.\footnote{In Paper Backpack, the identity for \mname{B} records its import of \mname{A}, but since it is definite, this is strictly redundant.} In a package with holes, each
-hole gets a fresh variable (within the package definition) as its
+hole (within the package definition) gets a fresh variable as its
identity, and all of the holes associated with package $P$ are recorded. Consider \pname{abcd-holes-1}:
\begin{example}
@@ -339,11 +615,20 @@ identity, and all of the holes associated with package $P$ are recorded. Conside
The identities of the four modules
are, in order, $\alpha_a$, $\alpha_b$, $\pname{abcd-holes-1}(\alpha_a,\alpha_b)$:\mname{C}, and
-$\pname{abcd-holes-1}(\alpha_a,\alpha_b)$:\mname{D}.\footnote{In Paper Backpack, the granularity is at the module level, so the subterms of \mname{C} and \mname{D} can differ.}
+$\pname{abcd-holes-1}(\alpha_a,\alpha_b)$:\mname{D}.\footnote{In Paper Backpack, the granularity is at the module level, so the subterms of \mname{C} and \mname{D} can differ.} We include both $\alpha_a$ and $\alpha_b$ in both \mname{C} and \mname{D}, regardless of the imports. When we link the package against an implementation of the hole, these variables are replaced with the identities of the modules we linked against.
-Consider now the module identities in the \m{Graph} instantiations in
-\pname{multinst}, shown in Figure 2 of the original Backpack paper (we have
-omitted it for brevity).
+Shaping proceeds in the same way as in Paper Backpack, except that the
+shaping judgment must also accept the package key
+$P(\vec{p\mapsto\alpha})$ so we can create identifiers with
+\textsf{mkident}. This implies we must know ahead of time what the holes
+of a package are.
+
+\paragraph{A full Backpack comparison}
+If you're curious about how the rest of the Backpack examples translate,
+look no further than this section.
+
+First, consider the module identities in the \m{Graph} instantiations in
+\pname{multinst}, shown in Figure 2 of the original Backpack paper.
In the definition of \pname{structures}, assume that the variables for
\m{Prelude} and \m{Array} are $\alpha_P$ and $\alpha_A$ respectively.
The identity of \m{Graph} is $\pname{structures}(\alpha_P, \alpha_A)$:\m{Graph}. Similarly, the identities of the two array implementations
@@ -378,103 +663,6 @@ Backpack paper still type checks. However, because we are operating at a coarse
granularity, modules may have spurious dependencies on holes that they don't
actually depend on, which means less type equalities may hold.
-Shaping proceeds in the same way as in Paper Backpack, except that the
-shaping judgment must also accept the package key
-$P(\vec{p\mapsto\alpha})$ so we can create identifiers with
-\textsf{mkident}. This implies we must know ahead of time what the holes
-of a package are.
-
-\subsection{Commentary}
-
-\begin{wrapfigure}{r}{0.4\textwidth}
-\begin{verbatim}
-package p where
- A :: ...
- -- B does not import A
- B = [ data T = T; f T = T ]
- C = [ import A; ... ]
-package q where
- A1 = [ ... ]
- A2 = [ ... ]
- include p (A as A1, B as B1)
- include p (A as A2, B as B2)
- Main = [
- import qualified B1
- import qualified B2
- y = B1.f B2.T
- ]
-\end{verbatim}
-\caption{The difference between package and module granularity}\label{fig:granularity}
-\end{wrapfigure}
-
-\paragraph{The sliding scale of granularity} The scheme we have described
-here is coarser-grained than Backpack's, and thus does not accept as many
-programs. Figure~\ref{fig:granularity} is a minimal example which doesn't type
-check in our new scheme.
-In Paper Backpack, the physical module identities of \m{B1} and \m{B2} are
-both $\K_B$, and so \m{Main} typechecks. However, in GHC Backpack,
-we assign module identities $\pname{p(q:A1)}$:$\m{B}$ and $\pname{p(q:A2)}$:$\m{B}$,
-which are not equal.
-
-Does this mean that Paper Backpack's form of granularity is \emph{better?}
-Not necessarily! First, we can always split packages into further subpackages
-which better reflect the internal hole dependencies, so it is always possible
-to rewrite a program to make it typecheck---just with more packages. Second,
-Paper Backpack's granularity is only one on a sliding scale; it is by no means
-the most extreme! You could imagine a version of Backpack where we desugared
-each \emph{expression} into a separate module.\footnote{Indeed, there are some
-languages which take this stance. (See Bob Harper's work.)} Then, even if \m{B} imported
-\m{A}, as long as it didn't use any types from \m{A} in the definition of
-\verb|T|, we would still consider the types equal. Finally, to understand
-what the physical module identity of a module is, in Paper Backpack I must
-understand the internal dependency structure of the modules in a package. This
-is a lot of work for the developer to think about; a more granular model
-is also easier to reason about.
-
-Nevertheless, finer granularity can be desirable from an end-user perspective.
-Usually, these circumstances arise when library-writers are forced to split their
-components into many separate packages, when they would much rather have written
-a single package. For example, if I define a data type in my library, and would
-like to define a \verb|Lens| instance for it, I would create a new package just
-for the instance, in order to avoid saddling users who aren't interested in lenses
-with an extra dependency. Another example is test suites, which have dependencies
-on various test frameworks that a user won't care about if they are not planning
-on testing the code. (Cabal has a special case for this, allowing the user
-to write effectively multiple packages in a single Cabal file.)
-
-\paragraph{Cabal dependency resolution} Currently, when we compile a Cabal
-package, Cabal goes ahead and resolves \verb|build-depends| entries with actual
-implementations, which we compile against. A planned addition to the package key,
-independent of Backpack, is to record the transitive dependency tree selected
-during this dependency resolution process, so that we can install \pname{libfoo-1.0}
-twice compiled against different versions of its dependencies.
-What is the relationship to this transitive dependency tree of \emph{packages},
-with the subterms of our package identities which are \emph{modules}? Does one
-subsume the other? In fact, these are separate mechanisms---two levels of indirections,
-so to speak.
-
-To illustrate, suppose I write a Cabal file with \verb|build-depends: foobar|. A reasonable assumption is that this translates into a
-Backpack package which has \verb|include foobar|. However, this is not
-actually a Paper Backpack package: Cabal's dependency solver has to
-rewrite all of these package references into versioned references
-\verb|include foobar-0.1|. For example, this is a pre-package:
-
-\begin{verbatim}
-package foo where
- include bar
-\end{verbatim}
-
-and this is a Paper Backpack package:
-
-\begin{verbatim}
-package foo-0.3[bar-0.1[baz-0.2]] where
- include bar-0.1[baz-0.2]
-\end{verbatim}
-
-This tree is very similar to the one tracking dependencies for holes,
-but we must record this tree \emph{even} when our package has no holes.
-As a final example, the full module
-identity of \m{B1} in Figure~\ref{fig:granularity} may actually be $\pname{p-0.9(q-1.0[p-0.9]:A1)}$:\m{B}.
\subsection{Implementation}
@@ -490,35 +678,6 @@ It is also important to note that we are \emph{willing to duplicate code};
processes like this already happen in other parts of the compiler
(such as inlining.)
-However, there is one major challenge for this scheme, related to
-\emph{dynamically linked libraries}. Consider this example:
-
-\begin{verbatim}
-package p where
- A :: [ ... ]
- B = [ ... ]
-package q where
- A = [ ... ]
- include p
- C = [ import A; import B; ... ]
-\end{verbatim}
-
-When we compile package \pname{q}, we end up compiling package keys
-\pname{q} and $\pname{p(q:A)}$, which turn into their respective libraries
-in the installed package database. When we need to statically link against
-these libraries, it doesn't matter that \pname{q} refers to code in $\pname{p(q:A)}$,
-and vice versa: the linker is building an executable and can resolve all
-of the symbols in one go. However, when the libraries in question are
-dynamic libraries \verb|libHSq.so| and \verb|libHSp(q:A).so|, this is now
-a \emph{circular dependency} between the two libraries, and most dynamic
-linkers will not be able to load either of these libraries.
-
-Our plan is to break the circularity by inlining the entire module \m{A}
-into $\pname{p(q:A)}$ when it is necessary (perhaps in other situations,
-\m{A} will be in another package and no inlining is necessary). The code
-in both situations should be exactly the same, so it should be completely
-permissible to consider them type-equal.
-
\paragraph{Relaxing package selection restrictions} As mentioned
previously, GHC is unable to select multiple packages with the same
package name (but different package keys). This restriction needs to be