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.,
UrandConsumable), - tools ported from
baseand from other critical haskell libraries, likelens, - new APIs for using system resources, e.g., file I/O in
System.IO.Resource.Linear, - 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.Linearis public facing and meant for users of linear-base whereasPrelude.Linear.Internalis meant as an internal prelude for development in linear-base itself. It is down deep in the module hierarchy, used throughout linear-base whilePrelude.Linearis at the top and no other modules import it.- Modules that have
Internalin 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.Functors andControl.Functors (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.LinearasLinearand not asFfor 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.