Linear base is more than a copy of things from base
with some function
arrows being replaced by linear arrows. Moreover, the goal is not exact
compliance with base
.
Linear base consists of the following:
- fundamental data structures, functions and classes that arise
naturally from wanting to do any linear development (e.g.,
Ur
andConsumable
), - tools ported from
base
and from other critical haskell libraries, likelens
, - new APIs for using system resources, e.g., file I/O in
System.IO.Resource
, - new abstractions made possible by linear types, like monad-free
mutable arrays in (
Data.Array.Mutable.Linear
).
There is a top-level Prelude.Linear
that is meant to be imported unqualified.
It does not include functors, monads, applicatives and so on because there are
multiple sensible ways to give linear arrows to these things. See this blog
post for details. This prelude includes:
- linear variants of definitions in
Prelude
, - a few pervasive utility definitions when programming with linear types.
Prelude.Linear
is public facing and meant for users of linear-base whereasPrelude.Linear.Internal
is meant as an internal prelude for development in linear-base itself. It is down deep in the module hierarchy, used throughout linear-base whilePrelude.Linear
is at the top and no other modules import it.- Modules that have
Internal
in the name are not meant to be public and have their functionality used and/or re-exported in public-facing modules.
This is the strategy that we've followed so far for developing
linear-base
:
-
If the definition is simple enough that there's only one sensible place to replace a function arrow by a linear arrow, do that. Example:
foldr :: (a %1-> b %1-> b) -> b %1-> [a] %1-> b foldr f z = \case [] -> z x:xs -> f x (foldr f z xs)
Otherwise, implement each sensible variant of the definition in dedicated modules. For instance, this is the case with
Data.Functor
s andControl.Functor
s (see this blog post). -
The ideas behind new definitions that are just now possible with linear types vary and each have unique concepts that are not addressed by a general strategy. These should be documented below if one of the following is true:
- there is an overarching concept that extends beyond a handful of modules. Or,
- There is an explicit departure away from the direction of
base
. (E.g., we decide there should be different laws for some type class already inbase
.)
We have established the following conventions in this project:
- use full words for Qualified imports, not abbreviations. For
instance, import
Data.Functor.Linear
asLinear
and not asF
for functor. - All public modules have an export list.
- Pure functions which modify a container take the
container as the last parameter (similar to functions in
Data.Map
). Monadic functions on containers take the containers as the first parameter (similar to functions inControl.Concurrent.MVar
). See issue #147 for some more details.