summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorIavor S. Diatchki <iavor.diatchki@gmail.com>2014-03-17 23:19:16 -0700
committerIavor S. Diatchki <iavor.diatchki@gmail.com>2014-03-17 23:20:02 -0700
commit3099e40d2737172c746a6456ddcd34b54e120aa0 (patch)
treeee94fab09b3c989eff407483c81a7f1a3fd90e88 /docs
parenta5ab610f8d7ea5ddbcfe2c27fa18fceb02923ee2 (diff)
downloadhaskell-3099e40d2737172c746a6456ddcd34b54e120aa0.tar.gz
Add some documentation about type-level literals.
I moved the "promoted literals" sub-section into a separate section, as many folks were not finding the docs. I also added some additional paragraphs describing the current state of the feature.
Diffstat (limited to 'docs')
-rw-r--r--docs/users_guide/glasgow_exts.xml178
1 files changed, 135 insertions, 43 deletions
diff --git a/docs/users_guide/glasgow_exts.xml b/docs/users_guide/glasgow_exts.xml
index 9dbd545069..33124122ef 100644
--- a/docs/users_guide/glasgow_exts.xml
+++ b/docs/users_guide/glasgow_exts.xml
@@ -6590,14 +6590,78 @@ Note that this requires <option>-XTypeOperators</option>.
</para>
</sect2>
-<sect2 id="promoted-literals">
-<title>Promoted Literals</title>
+<sect2 id="promotion-existentials">
+<title>Promoting existential data constructors</title>
+<para>
+Note that we do promote existential data constructors that are otherwise suitable.
+For example, consider the following:
+<programlisting>
+data Ex :: * where
+ MkEx :: forall a. a -> Ex
+</programlisting>
+Both the type <literal>Ex</literal> and the data constructor <literal>MkEx</literal>
+get promoted, with the polymorphic kind <literal>'MkEx :: forall k. k -> Ex</literal>.
+Somewhat surprisingly, you can write a type family to extract the member
+of a type-level existential:
+<programlisting>
+type family UnEx (ex :: Ex) :: k
+type instance UnEx (MkEx x) = x
+</programlisting>
+At first blush, <literal>UnEx</literal> seems poorly-kinded. The return kind
+<literal>k</literal> is not mentioned in the arguments, and thus it would seem
+that an instance would have to return a member of <literal>k</literal>
+<emphasis>for any</emphasis> <literal>k</literal>. However, this is not the
+case. The type family <literal>UnEx</literal> is a kind-indexed type family.
+The return kind <literal>k</literal> is an implicit parameter to <literal>UnEx</literal>.
+The elaborated definitions are as follows:
+<programlisting>
+type family UnEx (k :: BOX) (ex :: Ex) :: k
+type instance UnEx k (MkEx k x) = x
+</programlisting>
+Thus, the instance triggers only when the implicit parameter to <literal>UnEx</literal>
+matches the implicit parameter to <literal>MkEx</literal>. Because <literal>k</literal>
+is actually a parameter to <literal>UnEx</literal>, the kind is not escaping the
+existential, and the above code is valid.
+</para>
+
+<para>
+See also <ulink url="http://ghc.haskell.org/trac/ghc/ticket/7347">Trac #7347</ulink>.
+</para>
+</sect2>
+
+<sect2>
+<title>Promoting type operators</title>
+<para>
+Type operators are <emphasis>not</emphasis> promoted to the kind level. Why not? Because
+<literal>*</literal> is a kind, parsed the way identifiers are. Thus, if a programmer
+tried to write <literal>Either * Bool</literal>, would it be <literal>Either</literal>
+applied to <literal>*</literal> and <literal>Bool</literal>? Or would it be
+<literal>*</literal> applied to <literal>Either</literal> and <literal>Bool</literal>.
+To avoid this quagmire, we simply forbid promoting type operators to the kind level.
+</para>
+</sect2>
+
+
+</sect1>
+
+<sect1 id="type-level-literals">
+<title>Type-Level Literals</title>
+<para>
+GHC supports numeric and string literals at the type level, giving convenient
+access to a large number of predefined type-level constants.
+Numeric literals are of kind <literal>Nat</literal>, while string literals
+are of kind <literal>Symbol</literal>.
+This feature is enabled by the <literal>XDataKinds</literal>
+language extension.
+</para>
+
<para>
-Numeric and string literals are promoted to the type level, giving convenient
-access to a large number of predefined type-level constants. Numeric literals
-are of kind <literal>Nat</literal>, while string literals are of kind
-<literal>Symbol</literal>. These kinds are defined in the module
-<literal>GHC.TypeLits</literal>.
+The kinds of the literals and all other low-level operations for this feature
+are defined in module <literal>GHC.TypeLits</literal>. Note that the module
+defines some type-level operators that clash with their value-level
+counterparts (e.g. <literal>(+)</literal>). Import and export declarations
+referring to these operators require an explicit namespace
+annotation (see <xref linkend="explicit-namespaces"/>).
</para>
<para>
@@ -6632,56 +6696,84 @@ instance Has Point "y" Int where from (Point _ y) _ = y
example = from (Point 1 2) (Get :: Label "x")
</programlisting>
</para>
-</sect2>
-<sect2 id="promotion-existentials">
-<title>Promoting existential data constructors</title>
+<sect2 id="typelit-runtime">
+<title>Runtime Values for Type-Level Literals</title>
<para>
-Note that we do promote existential data constructors that are otherwise suitable.
-For example, consider the following:
+Sometimes it is useful to access the value-level literal assocaited with
+a type-level literal. This is done with the functions
+<literal>natVal</literal> and <literal>symbolVal</literal>. For example:
<programlisting>
-data Ex :: * where
- MkEx :: forall a. a -> Ex
+GHC.TypeLits> natVal (Proxy :: Proxy 2)
+2
</programlisting>
-Both the type <literal>Ex</literal> and the data constructor <literal>MkEx</literal>
-get promoted, with the polymorphic kind <literal>'MkEx :: forall k. k -> Ex</literal>.
-Somewhat surprisingly, you can write a type family to extract the member
-of a type-level existential:
+These functions are overloaded because they need to return a different
+result, depending on the type at which they are instantiated.
<programlisting>
-type family UnEx (ex :: Ex) :: k
-type instance UnEx (MkEx x) = x
+natVal :: KnownNat n => proxy n -> Integer
+
+-- instance KnownNat 0
+-- instance KnownNat 1
+-- instance KnownNat 2
+-- ...
</programlisting>
-At first blush, <literal>UnEx</literal> seems poorly-kinded. The return kind
-<literal>k</literal> is not mentioned in the arguments, and thus it would seem
-that an instance would have to return a member of <literal>k</literal>
-<emphasis>for any</emphasis> <literal>k</literal>. However, this is not the
-case. The type family <literal>UnEx</literal> is a kind-indexed type family.
-The return kind <literal>k</literal> is an implicit parameter to <literal>UnEx</literal>.
-The elaborated definitions are as follows:
+GHC discharges the constraint as soon as it knows what concrete
+type-level literal is being used in the program. Note that this works
+only for <emphasis>literals</emphasis> and not arbitrary type expressions.
+For example, a constraint of the form <literal>KnownNat (a + b)</literal>
+will <emphasis>not</emphasis> be simplified to
+<literal>(KnownNat a, KnownNat b)</literal>; instead, GHC will keep the
+constraint as is, until it can simplify <literal>a + b</literal> to
+a constant value.
+</para>
+</sect2>
+
+<para>
+It is also possible to convert a run-time integer or string value to
+the corresponding type-level literal. Of course, the resulting type
+literal will be unknown at compile-time, so it is hidden in an existential
+type. The conversion may be performed using <literal>someNatVal</literal>
+for integers and <literal>someSymbolVal</literal> for strings:
<programlisting>
-type family UnEx (k :: BOX) (ex :: Ex) :: k
-type instance UnEx k (MkEx k x) = x
+someNatVal :: Integer -> Maybe SomeNat
+SomeNat :: KnownNat n => Proxy n -> SomeNat
</programlisting>
-Thus, the instance triggers only when the implicit parameter to <literal>UnEx</literal>
-matches the implicit parameter to <literal>MkEx</literal>. Because <literal>k</literal>
-is actually a parameter to <literal>UnEx</literal>, the kind is not escaping the
-existential, and the above code is valid.
+The operations on strings are similar.
</para>
+<sect2 id="typelit-tyfuns">
+<title>Computing With Type-Level Naturals</title>
<para>
-See also <ulink url="http://ghc.haskell.org/trac/ghc/ticket/7347">Trac #7347</ulink>.
+GHC 7.8 can evaluate arithmetic expressions involving type-level natural
+numbers. Such expressions may be constructed using the type-families
+<literal>(+), (*), (^)</literal> for addition, multiplication,
+and exponentiation. Numbers may be compared using <literal>(&lt;=?)</literal>,
+which returns a promoted boolean value, or <literal>(&lt;=)</literal>, which
+compares numbers as a constraint. For example:
+<programlisting>
+GHC.TypeLits> natVal (Proxy :: Proxy (2 + 3))
+5
+</programlisting>
+</para>
+<para>
+At present, GHC is quite limited in its reasoning about arithmetic:
+it will only evalute the arithmetic type functions and compare the results---
+in the same way that it does for any other type function. In particular,
+it does not know more general facts about arithmetic, such as the commutativity
+and associativity of <literal>(+)</literal>, for example.
</para>
-</sect2>
-<sect2>
-<title>Promoting type operators</title>
<para>
-Type operators are <emphasis>not</emphasis> promoted to the kind level. Why not? Because
-<literal>*</literal> is a kind, parsed the way identifiers are. Thus, if a programmer
-tried to write <literal>Either * Bool</literal>, would it be <literal>Either</literal>
-applied to <literal>*</literal> and <literal>Bool</literal>? Or would it be
-<literal>*</literal> applied to <literal>Either</literal> and <literal>Bool</literal>.
-To avoid this quagmire, we simply forbid promoting type operators to the kind level.
+However, it is possible to perform a bit of "backwards" evaluation.
+For example, here is how we could get GHC to compute arbitrary logarithms
+at the type level:
+<programlisting>
+lg :: Proxy base -> Proxy (base ^ pow) -> Proxy pow
+lg _ _ = Proxy
+
+GHC.TypeLits> natVal (lg (Proxy :: Proxy 2) (Proxy :: Proxy 8))
+3
+</programlisting>
</para>
</sect2>