[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
 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>
 </Para>
 
 <Para>
@@ -78,6 +76,15 @@ for some nested declarations, where this would not be legal in Haskell
 </VarListEntry>
 
 <VarListEntry>
 </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>
 <Term>Calling out to C:</Term>
 <ListItem>
 <Para>
@@ -1341,17 +1348,142 @@ The libraries documentatation gives more details on all these
 
 </Sect1>
 
 
 </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">
 <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>
 <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.
 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.