[project @ 2000-05-19 12:00:47 by rrt]
[ghc-hetmet.git] / ghc / docs / users_guide / glasgow_exts.sgml
index 6cbb5fe..e1467fa 100644 (file)
@@ -12,9 +12,7 @@ the underlying facilities with which we implement Haskell.  Thus, you
 can get at the Raw Iron, if you are willing to write some non-standard
 code at a more primitive level.  You need not be “stuck” on
 performance because of the implementation costs of Haskell's
-“high-level” features—you can always code “under” them.  In an
-extreme case, you can write all your time-critical code in C, and then
-just glue it together with Haskell!
+“high-level” features—you can always code “under” them.  In an extreme case, you can write all your time-critical code in C, and then just glue it together with Haskell!
 </Para>
 
 <Para>
@@ -78,6 +76,15 @@ for some nested declarations, where this would not be legal in Haskell
 </VarListEntry>
 
 <VarListEntry>
+<Term>Pattern guards</Term>
+<ListItem>
+<Para>
+Instead of being a boolean expression, a guard is a list of qualifiers, exactly as in a list comprehension. See <XRef LinkEnd="pattern-guards">.
+</Para>
+</ListItem>
+</VarListEntry>
+
+<VarListEntry>
 <Term>Calling out to C:</Term>
 <ListItem>
 <Para>
@@ -1341,17 +1348,142 @@ The libraries documentatation gives more details on all these
 
 </Sect1>
 
+
+<Sect1 id="pattern-guards">
+<Title>Pattern guards</Title>
+
+<Para>
+<IndexTerm><Primary>Pattern guards (Glasgow extension)</Primary></IndexTerm>
+The discussion that follows is an abbreviated version of Simon Peyton Jones's original <ULink URL="http://research.microsoft.com/~simonpj/Haskell/guards.html">proposal</ULink>. (Note that the proposal was written before pattern guards were implemented, so refers to them as unimplemented.)
+</Para>
+
+<Para>
+Suppose we have an abstract data type of finite maps, with a
+lookup operation:
+
+<ProgramListing>
+lookup :: FiniteMap -> Int -> Maybe Int
+</ProgramListing>
+
+The lookup returns <Function>Nothing</Function> if the supplied key is not in the domain of the mapping, and <Function>(Just v)</Function> otherwise,
+where <VarName>v</VarName> is the value that the key maps to.  Now consider the following definition:
+</Para>
+
+<ProgramListing>
+clunky env var1 var2 | ok1 && ok2 = val1 + val2
+| otherwise  = var1 + var2
+where
+  m1 = lookup env var1
+  m2 = lookup env var2
+  ok1 = maybeToBool m1
+  ok2 = maybeToBool m2
+  val1 = expectJust m1
+  val2 = expectJust m2
+</ProgramListing>
+
+<Para>
+The auxiliary functions are 
+</Para>
+
+<ProgramListing>
+maybeToBool :: Maybe a -&gt; Bool
+maybeToBool (Just x) = True
+maybeToBool Nothing  = False
+
+expectJust :: Maybe a -&gt; a
+expectJust (Just x) = x
+expectJust Nothing  = error "Unexpected Nothing"
+</ProgramListing>
+
+<Para>
+What is <Function>clunky</Function> doing? The guard <Literal>ok1 &&
+ok2</Literal> checks that both lookups succeed, using
+<Function>maybeToBool</Function> to convert the <Function>Maybe</Function>
+types to booleans. The (lazily evaluated) <Function>expectJust</Function>
+calls extract the values from the results of the lookups, and binds the
+returned values to <VarName>val1</VarName> and <VarName>val2</VarName>
+respectively.  If either lookup fails, then clunky takes the
+<Literal>otherwise</Literal> case and returns the sum of its arguments.
+</Para>
+
+<Para>
+This is certainly legal Haskell, but it is a tremendously verbose and
+un-obvious way to achieve the desired effect.  Arguably, a more direct way
+to write clunky would be to use case expressions:
+</Para>
+
+<ProgramListing>
+clunky env var1 var1 = case lookup env var1 of
+  Nothing -&gt; fail
+  Just val1 -&gt; case lookup env var2 of
+    Nothing -&gt; fail
+    Just val2 -&gt; val1 + val2
+where
+  fail = val1 + val2
+</ProgramListing>
+
+<Para>
+This is a bit shorter, but hardly better.  Of course, we can rewrite any set
+of pattern-matching, guarded equations as case expressions; that is
+precisely what the compiler does when compiling equations! The reason that
+Haskell provides guarded equations is because they allow us to write down
+the cases we want to consider, one at a time, independently of each other. 
+This structure is hidden in the case version.  Two of the right-hand sides
+are really the same (<Function>fail</Function>), and the whole expression
+tends to become more and more indented. 
+</Para>
+
+<Para>
+Here is how I would write clunky:
+</Para>
+
+<ProgramListing>
+clunky env var1 var1
+  | Just val1 &lt;- lookup env var1
+  , Just val2 &lt;- lookup env var2
+  = val1 + val2
+...other equations for clunky...
+</ProgramListing>
+
+<Para>
+The semantics should be clear enough.  The qualifers are matched in order. 
+For a <Literal>&lt;-</Literal> qualifier, which I call a pattern guard, the
+right hand side is evaluated and matched against the pattern on the left. 
+If the match fails then the whole guard fails and the next equation is
+tried.  If it succeeds, then the appropriate binding takes place, and the
+next qualifier is matched, in the augmented environment.  Unlike list
+comprehensions, however, the type of the expression to the right of the
+<Literal>&lt;-</Literal> is the same as the type of the pattern to its
+left.  The bindings introduced by pattern guards scope over all the
+remaining guard qualifiers, and over the right hand side of the equation.
+</Para>
+
+<Para>
+Just as with list comprehensions, boolean expressions can be freely mixed
+with among the pattern guards.  For example:
+</Para>
+
+<ProgramListing>
+f x | [y] <- x
+    , y > 3
+    , Just z <- h y
+    = ...
+</ProgramListing>
+
+<Para>
+Haskell's current guards therefore emerge as a special case, in which the
+qualifier list has just one element, a boolean expression.
+</Para>
+</Sect1>
+
+
 <Sect1 id="glasgow-ccalls">
-<Title>Calling&nbsp;C directly from Haskell
-</Title>
+<Title>Calling C directly from Haskell</Title>
 
 <Para>
 <IndexTerm><Primary>C calls (Glasgow extension)</Primary></IndexTerm>
 <IndexTerm><Primary>&lowbar;ccall&lowbar; (Glasgow extension)</Primary></IndexTerm>
 <IndexTerm><Primary>&lowbar;casm&lowbar; (Glasgow extension)</Primary></IndexTerm>
-</Para>
-
-<Para>
 GOOD ADVICE: Because this stuff is not Entirely Stable as far as names
 and things go, you would be well-advised to keep your C-callery
 corraled in a few modules, rather than sprinkled all over your code.