GHC supports a small extension to the syntax of module
names: a module name is allowed to contain a dot
‘.’
. This is also known as the
“hierarchical module namespace” extension, because
it extends the normally flat Haskell module namespace into a
more flexible hierarchy of modules.
This extension has very little impact on the language
itself; modules names are always fully
qualified, so you can just think of the fully qualified module
name as “the module name”. In particular, this
means that the full module name must be given after the
module
keyword at the beginning of the
module; for example, the module A.B.C
must
begin
module A.B.C
It is a common strategy to use the as
keyword to save some typing when using qualified names with
hierarchical modules. For example:
import qualified Control.Monad.ST.Strict as ST
For details on how GHC searches for source and interface files in the presence of hierarchical modules, see Section 4.6.3, “The search path”.
GHC comes with a large collection of libraries arranged hierarchically; see the accompanying library documentation. There is an ongoing project to create and maintain a stable set of “core” libraries used by several Haskell compilers, and the libraries that GHC comes with represent the current status of that project. For more details, see Haskell Libraries.
The discussion that follows is an abbreviated version of Simon Peyton Jones's original proposal. (Note that the proposal was written before pattern guards were implemented, so refers to them as unimplemented.)
Suppose we have an abstract data type of finite maps, with a lookup operation:
lookup :: FiniteMap -> Int -> Maybe Int
The lookup returns Nothing
if the supplied key is not in the domain of the mapping, and (Just v)
otherwise,
where v
is the value that the key maps to. Now consider the following definition:
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
The auxiliary functions are
maybeToBool :: Maybe a -> Bool maybeToBool (Just x) = True maybeToBool Nothing = False expectJust :: Maybe a -> a expectJust (Just x) = x expectJust Nothing = error "Unexpected Nothing"
What is clunky
doing? The guard ok1 &&
ok2
checks that both lookups succeed, using
maybeToBool
to convert the Maybe
types to booleans. The (lazily evaluated) expectJust
calls extract the values from the results of the lookups, and binds the
returned values to val1
and val2
respectively. If either lookup fails, then clunky takes the
otherwise
case and returns the sum of its arguments.
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:
clunky env var1 var1 = case lookup env var1 of Nothing -> fail Just val1 -> case lookup env var2 of Nothing -> fail Just val2 -> val1 + val2 where fail = val1 + val2
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 (fail
), and the whole expression
tends to become more and more indented.
Here is how I would write clunky:
clunky env var1 var1 | Just val1 <- lookup env var1 , Just val2 <- lookup env var2 = val1 + val2 ...other equations for clunky...
The semantics should be clear enough. The qualifiers are matched in order.
For a <-
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
<-
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.
Just as with list comprehensions, boolean expressions can be freely mixed with among the pattern guards. For example:
f x | [y] <- x , y > 3 , Just z <- h y = ...
Haskell's current guards therefore emerge as a special case, in which the qualifier list has just one element, a boolean expression.
The recursive do-notation (also known as mdo-notation) is implemented as described in "A recursive do for Haskell", Levent Erkok, John Launchbury", Haskell Workshop 2002, pages: 29-37. Pittsburgh, Pennsylvania.
The do-notation of Haskell does not allow recursive bindings, that is, the variables bound in a do-expression are visible only in the textually following code block. Compare this to a let-expression, where bound variables are visible in the entire binding group. It turns out that several applications can benefit from recursive bindings in the do-notation, and this extension provides the necessary syntactic support.
Here is a simple (yet contrived) example:
import Control.Monad.Fix justOnes = mdo xs <- Just (1:xs) return xs
As you can guess justOnes
will evaluate to Just [1,1,1,...
.
The Control.Monad.Fix library introduces the MonadFix
class. It's definition is:
class Monad m => MonadFix m where mfix :: (a -> m a) -> m a
The function mfix
dictates how the required recursion operation should be performed. If recursive bindings are required for a monad,
then that monad must be declared an instance of the MonadFix
class.
For details, see the above mentioned reference.
The following instances of MonadFix
are automatically provided: List, Maybe, IO.
Furthermore, the Control.Monad.ST and Control.Monad.ST.Lazy modules provide the instances of the MonadFix class
for Haskell's internal state monad (strict and lazy, respectively).
There are three important points in using the recursive-do notation:
The recursive version of the do-notation uses the keyword mdo
(rather
than do
).
You should import Control.Monad.Fix
.
(Note: Strictly speaking, this import is required only when you need to refer to the name
MonadFix
in your program, but the import is always safe, and the programmers
are encouraged to always import this module when using the mdo-notation.)
As with other extensions, ghc should be given the flag -fglasgow-exts
The web page: http://www.cse.ogi.edu/PacSoft/projects/rmb contains up to date information on recursive monadic bindings.
Historical note: The old implementation of the mdo-notation (and most
of the existing documents) used the name
MonadRec
for the class and the corresponding library.
This name is not supported by GHC.
Parallel list comprehensions are a natural extension to list comprehensions. List comprehensions can be thought of as a nice syntax for writing maps and filters. Parallel comprehensions extend this to include the zipWith family.
A parallel list comprehension has multiple independent branches of qualifier lists, each separated by a `|' symbol. For example, the following zips together two lists:
[ (x, y) | x <- xs | y <- ys ]
The behavior of parallel list comprehensions follows that of zip, in that the resulting list will have the same length as the shortest branch.
We can define parallel list comprehensions by translation to regular comprehensions. Here's the basic idea:
Given a parallel comprehension of the form:
[ e | p1 <- e11, p2 <- e12, ... | q1 <- e21, q2 <- e22, ... ... ]
This will be translated to:
[ e | ((p1,p2), (q1,q2), ...) <- zipN [(p1,p2) | p1 <- e11, p2 <- e12, ...] [(q1,q2) | q1 <- e21, q2 <- e22, ...] ... ]
where `zipN' is the appropriate zip for the given number of branches.
GHC allows most kinds of built-in syntax to be rebound by
the user, to facilitate replacing the Prelude
with a home-grown version, for example.
You may want to define your own numeric class
hierarchy. It completely defeats that purpose if the
literal "1" means "Prelude.fromInteger
1
", which is what the Haskell Report specifies.
So the -fno-implicit-prelude
flag causes
the following pieces of built-in syntax to refer to
whatever is in scope, not the Prelude
versions:
Integer and fractional literals mean
"fromInteger 1
" and
"fromRational 3.2
", not the
Prelude-qualified versions; both in expressions and in
patterns.
However, the standard Prelude Eq
class
is still used for the equality test necessary for literal patterns.
Negation (e.g. "- (f x)
")
means "negate (f x)
" (not
Prelude.negate
).
In an n+k pattern, the standard Prelude
Ord
class is still used for comparison,
but the necessary subtraction uses whatever
"(-)
" is in scope (not
"Prelude.(-)
").
"Do" notation is translated using whatever
functions (>>=)
,
(>>)
, fail
, and
return
, are in scope (not the Prelude
versions). List comprehensions, and parallel array
comprehensions, are unaffected.
Similarly recursive do notation (see
Section 7.3.3, “The recursive do-notation
”) uses whatever
mfix
function is in scope, and arrow
notation (see Section 7.7, “Arrow notation
”)
uses whatever arr
,
(>>>)
, first
,
app
, (|||)
and
loop
functions are in scope.
The functions with these names that GHC finds in scope must have types matching those of the originals, namely:
fromInteger :: Integer -> N fromRational :: Rational -> N negate :: N -> N (-) :: N -> N -> N (>>=) :: forall a b. M a -> (a -> M b) -> M b (>>) :: forall a b. M a -> M b -> M b return :: forall a. a -> M a fail :: forall a. String -> M a
(Here N
may be any type,
and M
any type constructor.)
Be warned: this is an experimental facility, with
fewer checks than usual. Use -dcore-lint
to typecheck the desugared program. If Core Lint is happy
you should be all right.