A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/linear_types.html below:

Website Navigation


6.4.21. Linear types — Glasgow Haskell Compiler 9.12.2 User's Guide

6.4.21. Linear types¶
LinearTypes¶
Implies:

MonoLocalBinds

Since:

9.0.1

Status:

Experimental

Enable the linear arrow a %1 -> b and the multiplicity-polymorphic arrow a %m -> b.

This extension is currently considered experimental, expect bugs, warts, and bad error messages; everything down to the syntax is subject to change. See, in particular, Limitations below. We encourage you to experiment with this extension and report issues in the GHC bug tracker, adding the tag LinearTypes.

A function f is linear if: when its result is consumed exactly once, then its argument is consumed exactly once. Intuitively, it means that in every branch of the definition of f, its argument x must be used exactly once. Which can be done by

With -XLinearTypes, you can write f :: a %1 -> b to mean that f is a linear function from a to b. If UnicodeSyntax is enabled, the %1 -> arrow can be written as ⊸.

To allow uniform handling of linear a %1 -> b and unrestricted a -> b functions, there is a new function type a %m -> b. Here, m is a type of new kind Multiplicity. We have:

data Multiplicity = One | Many  -- Defined in GHC.Types

type a %1 -> b = a %One  -> b
type a  -> b = a %Many -> b

(See Datatype promotion).

We say that a variable whose multiplicity constraint is Many is unrestricted.

The multiplicity-polymorphic arrow a %m -> b is available in a prefix version as GHC.Exts.FUN m a b, which can be applied partially. See, however Limitations.

Linear and multiplicity-polymorphic arrows are always declared, never inferred. That is, if you don’t give an appropriate type signature to a function, it will be inferred as being a regular function of type a -> b. The same principle holds for representation polymorphism (see Inference and defaulting).

6.4.21.1. Expressions¶

When defining a function either as a lambda \x -> u or with equations f x = u, the multiplicity of the variable x will be inferred from the context. For equations, the context will typically be a type signature. For instance here is a linear function

f :: (a -> b) %1 -> a -> b
f g x = g x

In this example, g must be used linearly while x is unrestricted.

6.4.21.1.1. Bindings¶

Let and where bindings can be linear as well, the multiplicity of bindings is typically inferred

f :: A %1 -> B
g :: B %1 -> C

h :: A %1 -> C
h x = g y
  where
    y = f x

If you don’t want, or aren’t able, to rely on inference, let and where bindings can be annotated with a multiplicity

f :: A %1 -> B
g :: B %1 -> C

h :: A %1 -> C
h x = g y
  where
    %1 y = f x

The precise rules are, that you can annotate a binding with a multiplicity if:

When there’s no multiplicity annotation, the multiplicity is inferred as follows:

When -XMonoLocalBinds is off, the following also holds:

6.4.21.1.2. Strict patterns¶

GHC considers that non-variable lazy patterns consume the scrutinee with multiplicity Many. In practice, a pattern is strict (hence can be linear) if (otherwise the pattern is lazy):

Here are some examples of the impact on linear typing:

Without -XStrict:

-- good
let %1 x = u in …

-- good
let %1 !x = u in …

-- bad
let %1 (x, y) = u in …

-- good
let %Many (x, y) = u in …

-- good
let %1 !(x, y) = u in …

-- good
let %1 (!(x, y)) = u in …

-- inferred unrestricted
let (x, y) = u in …

-- can be inferred linear
case u of (x, y) -> …

-- inferred unrestricted
case u of ~(x, y) -> …

With -XStrict:

-- good
let %1 x = u in …

-- good
let %1 !x = u in …

-- good
let %1 (x, y) = u in …

-- bad
let %1 ~(x, y) = u in …

-- good
let %Many ~(x, y) = u in …

-- can be inferred linear
let (x, y) = u in …

-- inferred unrestricted
let ~(x, y) = u in …
6.4.21.2. Data types¶

By default, all fields in algebraic data types are linear (even if -XLinearTypes is not turned on). Given

the value MkT1 x can be constructed and deconstructed in a linear context:

construct :: a %1 -> T1 a
construct x = MkT1 x

deconstruct :: T1 a %1 -> a
deconstruct (MkT1 x) = x  -- must consume `x` exactly once

When used as a value, MkT1 is given a multiplicity-polymorphic type: MkT1 :: forall {m} a. a %m -> T1 a. This makes it possible to use MkT1 in higher order functions. The additional multiplicity argument m is marked as inferred (see Inferred vs. specified type variables), so that there is no conflict with visible type application. When displaying types, unless -XLinearTypes is enabled, multiplicity polymorphic functions are printed as regular functions (see Printing multiplicity-polymorphic types); therefore constructors appear to have regular function types.

mkList :: [a] -> [T1 a]
mkList xs = map MkT1 xs

Hence the linearity of type constructors is invisible when -XLinearTypes is off.

Whether a data constructor field is linear or not can be customized using the GADT syntax. Given

data T2 a b c where
    MkT2 :: a -> b %1 -> c %1 -> T2 a b c -- Note unrestricted arrow in the first argument

the value MkT2 x y z can be constructed only if x is unrestricted. On the other hand, a linear function which is matching on MkT2 x y z must consume y and z exactly once, but there is no restriction on x.

It is also possible to define a multiplicity-polymorphic field:

data T3 a m where
    MkT3 :: a %m -> T3 a m

While linear fields are generalized (MkT1 :: forall {m} a. a %m -> T1 a in the previous example), multiplicity-polymorphic fields are not; it is not possible to directly use MkT3 as a function a -> T3 a One.

If LinearTypes is disabled, all fields are considered to be linear fields, including GADT fields defined with the -> arrow.

In a newtype declaration, the field must be linear. Attempting to write an unrestricted newtype constructor with GADT syntax results in an error.

6.4.21.3. Printing multiplicity-polymorphic types¶

If LinearTypes is disabled, multiplicity variables in types are defaulted to Many when printing, in the same manner as described in Printing representation-polymorphic types. In other words, without LinearTypes, multiplicity-polymorphic functions a %m -> b are printed as normal Haskell2010 functions a -> b. This allows existing libraries to be generalized to linear types in a backwards-compatible manner; the general types are visible only if the user has enabled LinearTypes. (Note that a library can declare a linear function in the contravariant position, i.e. take a linear function as an argument. In this case, linearity cannot be hidden; it is an essential part of the exposed interface.)

6.4.21.4. Limitations¶

Linear types are still considered experimental and come with several limitations. If you have read the full design in the proposal (see Design and further reading below), here is a run down of the missing pieces.

6.4.21.5. Design and further reading¶

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4