From: simonpj Date: Mon, 7 Feb 2005 09:55:54 +0000 (+0000) Subject: [project @ 2005-02-07 09:55:54 by simonpj] X-Git-Tag: Initial_conversion_from_CVS_complete~1107 X-Git-Url: http://git.megacz.com/?p=ghc-hetmet.git;a=commitdiff_plain;h=e25528e60aef15cf6697b4a30217f1f1f22e9aa0 [project @ 2005-02-07 09:55:54 by simonpj] Better documentation for unboxed types; merge to STABLE --- diff --git a/ghc/docs/users_guide/glasgow_exts.xml b/ghc/docs/users_guide/glasgow_exts.xml index 765ff85..ff46b39 100644 --- a/ghc/docs/users_guide/glasgow_exts.xml +++ b/ghc/docs/users_guide/glasgow_exts.xml @@ -279,7 +279,7 @@ became out of date, and wrong information is worse than none. The Real Truth about what primitive types there are, and what operations work over those types, is held in the file -fptools/ghc/compiler/prelude/primops.txt. +fptools/ghc/compiler/prelude/primops.txt.pp. This file is used directly to generate GHC's primitive-operation definitions, so it is always correct! It is also intended for processing into text. @@ -343,11 +343,16 @@ it is accidental that it is represented by a pointer. If a pointer represents a primitive value, then it really does point to that value: no unevaluated thunks, no indirections…nothing can be at the other end of the pointer than the primitive value. +A numerically-intensive program using unboxed types can +go a lot faster than its “standard” +counterpart—we saw a threefold speedup on one example. -There are some restrictions on the use of primitive types, the main -one being that you can't pass a primitive value to a polymorphic +There are some restrictions on the use of primitive types: + +The main restriction +is that you can't pass a primitive value to a polymorphic function or store one in a polymorphic data type. This rules out things like [Int#] (i.e. lists of primitive integers). The reason for this restriction is that polymorphic @@ -359,11 +364,33 @@ attempt to dereference the pointer, with disastrous results. Even worse, the unboxed value might be larger than a pointer (Double# for instance). + + You cannot bind a variable with an unboxed type +in a top-level binding. + + You cannot bind a variable with an unboxed type +in a recursive binding. + + You may bind unboxed variables in a (non-recursive, +non-top-level) pattern binding, but any such variable causes the entire +pattern-match +to become strict. For example: + + data Foo = Foo Int Int# - -Nevertheless, A numerically-intensive program using unboxed types can -go a lot faster than its “standard” -counterpart—we saw a threefold speedup on one example. + f x = let (Foo a b, w) = ..rhs.. in ..body.. + +Since b has type Int#, the entire pattern +match +is strict, and the program behaves as if you had written + + data Foo = Foo Int Int# + + f x = case ..rhs.. of { (Foo a b, w) -> ..body.. } + + + + @@ -398,21 +425,19 @@ values, but they avoid the heap allocation normally associated with using fully-fledged tuples. When an unboxed tuple is returned, the components are put directly into registers or on the stack; the unboxed tuple itself does not have a composite representation. Many -of the primitive operations listed in this section return unboxed +of the primitive operations listed in primops.txt.pp return unboxed tuples. +In particular, the IO and ST monads use unboxed +tuples to avoid unnecessary allocation during sequences of operations. There are some pretty stringent restrictions on the use of unboxed tuples: - - - - - Unboxed tuple types are subject to the same restrictions as +Values of unboxed tuple types are subject to the same restrictions as other unboxed types; i.e. they may not be stored in polymorphic data structures or passed to polymorphic functions. @@ -421,56 +446,46 @@ structures or passed to polymorphic functions. - Unboxed tuples may only be constructed as the direct result of -a function, and may only be deconstructed with a case expression. -eg. the following are valid: - - - -f x y = (# x+1, y-1 #) -g x = case f x x of { (# a, b #) -> a + b } - - - -but the following are invalid: +No variable can have an unboxed tuple type, nor may a constructor or function +argument have an unboxed tuple type. The following are all illegal: -f x y = g (# x, y #) -g (# x, y #) = x + y - + data Foo = Foo (# Int, Int #) + f :: (# Int, Int #) -> (# Int, Int #) + f x = x - - - + g :: (# Int, Int #) -> Int + g (# a,b #) = a - - No variable can have an unboxed tuple type. This is illegal: - - - -f :: (# Int, Int #) -> (# Int, Int #) -f x = x + h x = let y = (# x,x #) in ... - - -because x has an unboxed tuple type. - - - - -Note: we may relax some of these restrictions in the future. - - - -The IO and ST monads use unboxed -tuples to avoid unnecessary allocation during sequences of operations. +The typical use of unboxed tuples is simply to return multiple values, +binding those multiple results with a case expression, thus: + + f x y = (# x+1, y-1 #) + g x = case f x x of { (# a, b #) -> a + b } + +You can have an unboxed tuple in a pattern binding, thus + + f x = let (# p,q #) = h x in ..body.. + +If the types of p and q are not unboxed, +the resulting binding is lazy like any other Haskell pattern binding. The +above example desugars like this: + + f x = let t = case h x o f{ (# p,q #) -> (p,q) + p = fst t + q = snd t + in ..body.. + +Indeed, the bindings can even be recursive.