Skip to content

Latest commit

 

History

History
95 lines (76 loc) · 3.96 KB

DESIGN.md

File metadata and controls

95 lines (76 loc) · 3.96 KB

Design

Overall architecture

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 and Consumable),
  • tools ported from base and from other critical haskell libraries, like lens,
  • 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.

Module structure

  • Prelude.Linear is public facing and meant for users of linear-base whereas Prelude.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 while Prelude.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.

General implementation strategy

This is the strategy that we've followed so far for developing linear-base:

  1. 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 and Control.Functors (see this blog post).

  2. 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 in base.)

Conventions

We have established the following conventions in this project:

  • use full words for Qualified imports, not abbreviations. For instance, import Data.Functor.Linear as Linear and not as F 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 in Control.Concurrent.MVar). See issue #147 for some more details.