This is a guide to using the Glasgow Haskell compilation (GHC) system. It is a batch compiler for the Haskell 1.4 language, with support for various Glasgow-only extensions.
Many people will use GHC very simply: compile some modules -- `ghc -c -O Foo.hs Bar.hs'; and link them -- `ghc -o wiggle -O Foo.o Bar.o'.
But if you need to do something more complicated, GHC can do that, too:
ghc -c -O -fno-foldr-build -dcore-lint -fvia-C -ddump-simpl Foo.lhs
Stay tuned -- all will be revealed!
In this document, we assume that GHC has been installed at your site as `ghc'. If you are unfamiliar with the conventions of UNIX compilers, the material in section 18 Tutorial material about this compilation system may help.
On the World-Wide Web, there are several URLs of likely interest:
Haskell home page -- `http://haskell.org/' GHC home page -- `http://www.dcs.gla.ac.uk/fp/software/ghc/' Glasgow FP group page -- `http://www.dcs.gla.ac.uk/fp/' comp.lang.functional FAQ -- `http://www.cs.nott.ac.uk/Department/Staff/mpj/faq.html'
We run two mailing lists about Glasgow Haskell. We encourage you to join, as you feel is appropriate.
subscribe glasgow-haskell-users My Name <m.y.self@bigbucks.com>(The last bit is your all-important e-mail address, of course.) To communicate with your fellow users, send mail to `glasgow-haskell-users'. To contact the list administrator, send mail to `glasgow-haskell-users-request'. An archive of the list is available on the Web at:
http://www.dcs.gla.ac.uk/mail-www/glasgow-haskell-users
subscribe glasgow-haskell-bugs My Name <m.y.self@hackers.r.us>Again, you may contact the list administrator at `glasgow-haskell-bugs-request'. And, yes, an archive of the list is available on the Web at:
http://www.dcs.gla.ac.uk/mail-www/glasgow-haskell-bugs
There is also the general Haskell mailing list. Subscribe by sending email to `majordomo@dcs.gla.ac.uk', with the usual message body:
subscribe haskell My Name <m.y.self@fp.rules.ok.org>
Some Haskell-related discussion takes place in the Usenet newsgroup `comp.lang.functional'. (But note: news is basically dead at Glasgow. That's one reason Glaswegians aren't too active in c.f.l.)
The main anonymous-FTP site for Glasgow Haskell is `ftp.dcs.gla.ac.uk', in `pub/haskell/glasgow/'. "Important" bits are mirrored at other Haskell archive sites (and we have their stuff, too).
Changes made since 2.08:
In 2.09, we've made extensive changes to the libraries that provide access to various GHC extensions. Many of these extensions are now provided by Hugs, and as a result we are now using a common set of extension libraries.
Briefly, the changes are as follows (for the definition of the new libraries, see the section on GHC/Hugs libraries in the User Guide).
GHC 2.08 is a minor upgrade of GHC 2.07, and is released as source only. It represents work done through September '97.
Here's a list of the changes made since GHC 2.07:
The following changes were made to Happy:
GHC 2.06 is a minor upgrade of GHC 2.05, and is released as source only. It represents work done through August '97.
Here's a list of the changes made since GHC 2.05:
GHC 2.04 is a minor upgrade of GHC 2.02 (and the bugfix release, 2.03), representing work done through May '97. This new release adds the following:
http://www.cse.ogi.edu/~simonpj/quantification.htmlExistential types coming, but not done yet.
http://www.cse.ogi.edu/~simonpj/guards.html
http://www.dcs.gla.ac.uk/fp/software/ghc/ghc-bugs.htmlNo doubt entries for 2.04 will be added here as well :-)
http://www.dcs.gla.ac.uk/fp/software/ghc/ghc-doc/install-guide.html
In addition to the above, we've made the following minor changes to the GHC libraries/our implementation of the Haskell standard prelude:
data Lift a = Lift ayou might need it someday...
--Renamed functions (old name in square brackets) openFd :: FilePath -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd -- [openChannel] fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset --[seekChannel] fdRead :: Fd -> ByteCount -> IO (String, ByteCount) --[readChannel] fdWrite :: Fd -> String -> IO ByteCount --[writeChannel] fdClose :: Fd -> IO () --[closeChannel] setFdOption :: Fd -> FdOption -> Bool -> IO () --[setChannelOption] queryFdOption :: Fd -> FdOption -> IO Bool --[queryChannelOption] dup :: Fd -> IO Fd --[dupChannel] dupTo :: Fd -> Fd -> IO () --[dupChannelTo] data FdOption = AppendOnWrite | CloseOnExec | NonBlockingRead --[ChannelOption] getFdStatus :: Fd -> IO FileStatus --[getChannelStatus] -- New data structure collecting together misc flags passed to openFd data OpenFileFlags = OpenFileFlags { append :: Bool, exclusive :: Bool, noctty :: Bool, nonBlock :: Bool, trunc :: Bool } --New ops for converting between Fd and Handle: fdToHandle :: Fd -> IO Handle handleToFd :: Handle -> IO Fd intToFd :: Int -> Fd -- use with care.
GHC 2.03 is a minor upgrade of GHC 2.02. It differs in the following ways:
http://www.cse.ogi.edu/~simonpj/ghc-bugs.htmlOne bug remains un-fixes, namely the crash when there's an empty comment at the end of file. It's wierd!
None of the bugs in GHC 2.02 are show-stoppers, so you'll only want to upgrade if you are a build-from-source junkie and the bugs are irritating you.
Apart from bug-fixes, which are itemized elsewhere, the exact language and standard-library changes are as follows:
In addition, we've made following changes to GHC libraries/GHC's implementation of the Haskell standard prelude:
Release 2.02 is the first release of Glasgow Haskell for Haskell 1.4.
The announcement for this release is distributed as `ANNOUNCE-2.02' in the top-level directory. It contains very important caveats about 2.02, which we do not repeat here!
Information about "what's ported to which machine" is in the Installation Guide. Since 2.01, we've added support for Win32 (Windows NT and Windows 95).
GHC 2.02 is a compiler for Haskell 1.4 and, as such, introduces a bunch of user-visible changes. The GHC user's guide has a section to help you upgrade your programs to Haskell 1.4 from 1.2; all user-visible changes are described there (and not repeated here).
The libraries have been completely reorganised. There's a description in section 10 System libraries.
2.02 is released together with Green Card, a foreign-language interface generator for Haskell. More details elsewhere...
The 2.02 compiler has the following known deficiencies:
We used to include the release notes back to the dawn of time in this document. Made for a nice long document, but it wasn't that interesting. If you would like to see old release notes, just ask; we've still got 'em.
Command-line arguments are either options or file names.
Command-line options begin with `-'. They may not be grouped: `-vO' is different from `-v -O'. Options need not precede filenames: e.g., `ghc *.o -o foo'. All options are processed and then applied to all files; you cannot, for example, invoke `ghc -c -O1 Foo.hs -O2 Bar.hs' to apply different optimisation levels to the files `Foo.hs' and `Bar.hs'. For conflicting options, e.g., `-c -S', we reserve the right to do anything we want. (Usually, the last one applies.)
Options related to profiling, Glasgow extensions to Haskell (e.g., unboxed values), Concurrent and Parallel Haskell are described in section 7 Profiling Haskell programs, section 8 Glasgow extensions to Haskell, and section 11 Concurrent and Parallel Haskell, respectively.
File names with "meaningful" suffixes (e.g., `.lhs' or `.o') cause the "right thing" to happen to those files.
Files with other suffixes (or without suffixes) are passed straight to the linker.
A good option to start with is the `-help' (or `-?') option.
GHC spews a long message to standard output and then exits.
The `-v' option makes GHC verbose: it reports its version number and shows (on stderr) exactly how it invokes each phase of the compilation system. Moreover, it passes the `-v' flag to most phases; each reports its version number (and possibly some other information).
Please, oh please, use the `-v' option when reporting bugs! Knowing that you ran the right bits in the right order is always the first thing we want to verify.
If you're just interested in the compiler version number, the `--version' option prints out a one-line string containing the requested info.
The basic task of the `ghc' driver is to run each input file through the right phases (parsing, linking, etc.).
The first phase to run is determined by the input-file suffix, and the last phase is determined by a flag. If no relevant flag is present, then go all the way through linking. This table summarises:
phase of the suffix saying flag saying (suffix of) compilation system "start here" "stop after" output file ---------------------------------------------------------------- literate pre-processor .lhs - - C pre-processor (opt.) - - - Haskell compiler .hs -C, -S .hc, .s C compiler (opt.) .hc or .c -S .s assembler .s -c .o linker other - a.out
Thus, a common invocation would be: `ghc -c Foo.hs'
Note: What the Haskell compiler proper produces depends on whether a native-code generator is used (producing assembly language) or not (producing C).
The option `-cpp' must be given for the C pre-processor phase to be run, that is, the pre-processor will be run over your Haskell source file before continuing.
The option `-E' runs just the pre-processing passes of the compiler, outputting the result on stdout before stopping. If used in conjunction with -cpp, the output is the code blocks of the original (literal) source after having put it through the grinder that is the C pre-processor. Sans `-cpp', the output is the de-litted version of the original source.
The option `-optcpp-E' runs just the pre-processing stage of the C-compiling phase, sending the result to stdout. (For debugging or obfuscation contests, usually.)
The `-O*' options specify convenient "packages" of optimisation flags; the `-f*' options described later on specify individual optimisations to be turned on/off; the `-m*' options specify machine-specific optimisations to be turned on/off.
There are many options that affect the quality of code produced by GHC. Most people only have a general goal, something like "Compile quickly" or "Make my program run like greased lightning." The following "packages" of optimisations (or lack thereof) should suffice.
Once you choose a `-O*' "package," stick with it -- don't chop and change. Modules' interfaces will change with a shift to a new `-O*' option, and you may have to recompile a large chunk of all importing modules before your program can again be run safelysection 15.2 The recompilation checker.
At Glasgow, we don't use a `-O*' flag for day-to-day work. We use `-O' to get respectable speed; e.g., when we want to measure something. When we want to go for broke, we tend to use `-O -fvia-C -O2-for-C' (and we go for lots of coffee breaks).
The easiest way to see what `-O' (etc) "really mean" is to run with `-v', then stand back in amazement. Alternatively, just look at the `@HsC_minus<blah>' lists in the `ghc' driver script.
Flags can be turned off individually. (NB: I hope you have a good reason for doing this....) To turn off the `-ffoo' flag, just use the `-fno-foo' flag. So, for example, you can say `-O2 -fno-strictness', which will then drop out any running of the strictness analyser.
The options you are most likely to want to turn off are: `-fno-strictness' (strictness analyser [because it is sometimes slow]), `-fno-specialise' (automatic specialisation of overloaded functions [because it makes your code bigger]) [US spelling also accepted], and `-fno-foldr-build'.
Should you wish to turn individual flags on, you are advised to use the `-Ofile' option, described above. Because the order in which optimisation passes are run is sometimes crucial, it's quite hard to do with command-line options.
Here are some "dangerous" optimisations you might want to try:
Some flags only make sense for particular target platforms.
Foo.hc:533: fixed or forbidden register was spilled. This may be due to a compiler bug or to impossible asm statements or clauses.Just give some registers back with `-monly-N-regs'. Try `3' first, then `2'. If `2' doesn't work, please report the bug to us.
The C compiler (GCC) is run with `-O' turned on. (It has to be, actually).
If you want to run GCC with `-O2' -- which may be worth a few percent in execution speed -- you can give a `-O2-for-C' option.
GHC has a selection of options that select which types of non-fatal error messages, otherwise known as warnings, can be generated during compilation. By default, you get a standard set of warnings which are generally likely to indicate bugs in your program. These are: `-fwarn-overlpapping-patterns' and `-fwarn-missing-methods'. The following flags are simple ways to select standard "packages" of warnings:
The full set of warning options is described below. To turn off any warning, simply give the corresponding `-fno-warn-...' option on the command line.
f :: String -> Int f [] = 0 f (_:xs) = 1 f "2" = 2 g [] = 2where the last pattern match in `f' won't ever be reached, as the second pattern overlaps it. More often than not, redundant patterns is a programmer mistake/error, so this option is enabled by default.
If you would like GHC to check that every top-level value has a type signature, use the `-fsignatures-required' option.
If you're feeling really paranoid, the `-dcore-lint' option is a good choice. It turns on heavyweight intra-pass sanity-checking within GHC. (It checks GHC's sanity, not yours.)
When compiling a Haskell module, GHC may produce several files of output (usually two).
One file is usually an interface file. If compiling `bar/Foo.hs', the interface file would normally be `bar/Foo.hi'. The interface output may be directed to another file `bar2/Wurble.iface' with the option `-ohi bar2/Wurble.iface' (not recommended).
To avoid generating an interface file at all, use a `-nohi' option.
The compiler does not overwrite an existing `.hi' interface file if the new one is byte-for-byte the same as the old one; this is friendly to `make'. When an interface does change, it is often enlightening to be informed. The `-hi-diffs' option will make `ghc' run `diff' on the old and new `.hi' files. You can also record the difference in the interface file itself, the `-keep-hi-diffs' option takes care of that.
The `.hi' files from GHC 2.xx contain "usage" information which changes often and uninterestingly. If you really want to see these changes reported, you need to use the `-hi-diffs-with-usages' option.
GHC's non-interface output normally goes into a `.hc', `.o', etc., file, depending on the last-run compilation phase. The option `-o foo' re-directs the output of that last-run phase to file `foo'.
Note: this "feature" can be counterintuitive: `ghc -C -o foo.o foo.hs' will put the intermediate C code in the file `foo.o', name notwithstanding!
EXOTICA: But the `-o' option isn't of much use if you have several input files... Non-interface output files are normally put in the same directory as their corresponding input file came from. You may specify that they be put in another directory using the `-odir <dir>' (the "Oh, dear" option). For example:
% ghc -c parse/Foo.hs parse/Bar.hs gurgle/Bumble.hs -odir `arch`
The output files, `Foo.o', `Bar.o', and `Bumble.o' would be put into a subdirectory named after the architecture of the executing machine (`sun4', `mips', etc). The directory must already exist; it won't be created.
Note that the `-odir' option does not affect where the interface files are put. In the above example, they would still be put in `parse/Foo.hi', `parse/Bar.hi', and `gurgle/Bumble.hi'.
MORE EXOTICA: The `-osuf <suffix>' will change the `.o' file suffix for object files to whatever you specify. (We use this in compiling the prelude.)
Similarly, the `-hisuf <suffix>' will change the `.hi' file suffix for non-system interface files. This can be useful when you are trying to compile a program several ways, all in the same directory. The suffix given is used for all interfaces files written, and for all non-system interface files that your read.
The `-hisuf'/`-osuf' game is useful if you want to compile a program with both GHC and HBC (say) in the same directory. Let HBC use the standard `.hi'/`.o' suffixes; add `-hisuf g_hi -osuf g_o' to your `make' rule for GHC compiling...
NB: A change from 0.26 and before: Before, you might have said `-hisuf _g.hi -osuf _g.o'; now, the `.' is assumed and you specify what comes after it. (This is a more portable solution for the long term.)
FURTHER EXOTICA: If you are doing a normal `.hs'-to-`.o' compilation but would like to hang onto the intermediate `.hc' C file, just throw in a `-keep-hc-file-too' option. If you would like to look at the assembler output, toss in a `-keep-s-file-too', too.
SAVING GHC STDERR OUTPUT: Sometimes, you may cause GHC to be rather chatty on standard error; with `-fshow-import-specs', for example. You can instruct GHC to append this output to a particular log file with a `-odump <blah>' option.
TEMPORARY FILES: If you have trouble because of running out of space in `/tmp/' (or wherever your installation thinks temporary files should go), you may use the `-tmpdir <dir>' option to specify an alternate directory. For example, `-tmpdir .' says to put temporary files in the current working directory.
BETTER IDEA FOR TEMPORARY FILES: Use your `TMPDIR' environment variable. Set it to the name of the directory where temporary files should be put. GCC and other programs will honour the `TMPDIR' variable as well.
EVEN BETTER IDEA: Set the `TMPDIR' variable when building GHC, and never worry about `TMPDIR' again. (see the build documentation).
In your program, you import a module `Foo' by saying `import Foo'. GHC goes looking for an interface file, `Foo.hi'. It has a builtin list of directories (notably including `.') where it looks.
The `-i<dirs>' option prepends a colon-separated list of `dirs' to the "import directories" list.
A plain `-i' resets the "import directories" list back to nothing.
GHC normally imports `Prelude.hi' files for you. If you'd rather it didn't, then give it a `-fno-implicit-prelude' option. You are unlikely to get very far without a Prelude, but, hey, it's a free country.
If you are using a system-supplied non-Prelude library (e.g., the HBC library), just use a `-syslib hbc' option (for example). The right interface files should then be available.
Once a Haskell module has been compiled to C (`.hc' file), you may wish to specify where GHC tells the C compiler to look for `.h' files. (Or, if you are using the `-cpp' option, where it tells the C pre-processor to look...) For this purpose, use a `-I<dir>' in the usual C-ish way.
Pragmas: Interface files are normally jammed full of compiler-produced pragmas, which record arities, strictness info, etc. If you think these pragmas are messing you up (or you are doing some kind of weird experiment), you can tell GHC to ignore them with the `-fignore-interface-pragmas' option.
When compiling without optimisations on, the compiler is extra-careful about not slurping in data constructors and instance declarations that it will not need. If you believe it is getting it wrong and not importing stuff which you think it should, this optimisation can be turned off with `-fno-prune-tydecls' and `-fno-prune-instdecls'.
See also section 4.10 Linking and consistency-checking, which describes how the linker finds standard Haskell libraries.
The C pre-processor `cpp' is run over your Haskell code only if the `-cpp' option is given. Unless you are building a large system with significant doses of conditional compilation, you really shouldn't need it.
The `ghc' driver pre-defines several macros:
Options other than the above can be forced through to the C pre-processor with the `-opt' flags (see section 4.13.2 Forcing options to a particular phase.).
A small word of warning: `-cpp' is not friendly to "string gaps".. In other words, strings such as the following:
strmod = "\ \ p \ \ "
don't work with `-cpp'; `/usr/bin/cpp' elides the backslash-newline pairs.
However, it appears that if you add a space at the end of the line, then `cpp' (at least GNU `cpp' and possibly other `cpp's) leaves the backslash-space pairs alone and the string gap works as expected.
At the moment, quite a few common C-compiler options are passed on quietly to the C compilation of Haskell-compiler-generated C files. THIS MAY CHANGE. Meanwhile, options so sent are:
`-Wall' get all warnings from GCC `-ansi' do ANSI C (not K&R) `-pedantic' be so `-dgcc-lint' (hack) short for "make GCC very paranoid"
If you are compiling with lots of `ccalls', etc., you may need to
tell the C compiler about some `#include' files. There is no real
pretty way to do this, but you can use this hack from the
command-line:
% ghc -c '-#include <X/Xlib.h>' Xstuff.lhs
GHC has to link your code with various libraries, possibly including: user-supplied, GHC-supplied, and system-supplied (`-lm' math library, for example).
-l equivalent description ------------------------------------------------------------- -lHSrts,-lHSclib basic runtime libraries -lHS standard Prelude library -lHS_cbits C support code for standard Prelude library -lgmp GNU multi-precision library (for Integers)
The compiler is itself a Haskell program, so it has a tweakable runtime-system (RTS), just like any other Haskell program.
For all `<size>'s: If the last character of `size' is a K, multiply by 1000; if an M, by 1,000,000; if a G, by 1,000,000,000. Sizes are always in bytes, not words. Good luck on the G's (I think the counter is still only 32-bits [WDP])!
For the full story on using GHC for concurrent & parallel Haskell programming, please see Section 11 Concurrent and Parallel Haskell.
HACKER TERRITORY. HACKER TERRITORY. (You were warned.)
You may specify that a different program be used for one of the phases of the compilation system, in place of whatever the driver `ghc' has wired into it. For example, you might want to try a different assembler. The `-pgm<phase-code><program-name>' option to `ghc' will cause it to use <program-name> for phase <phase-code>, where the codes to indicate the phases are:
code phase ------------------------------------ L literate pre-processor P C pre-processor (if -cpp only) C Haskell compiler c C compiler a assembler l linker
The preceding sections describe driver options that are mostly applicable to one particular phase. You may also force a specific option `<option>' to be passed to a particular phase `<phase-code>' by feeding the driver the option `-opt<phase-code><option>'. The codes to indicate the phases are the same as in the previous section.
So, for example, to force an `-Ewurble' option to the assembler, you would tell the driver `-opta-Ewurble' (the dash before the E is required).
Besides getting options to the Haskell compiler with `-optC<blah>', you can get options through to its runtime system with `-optCrts<blah>'.
So, for example: when I want to use my normal driver but with my
profiled compiler binary, I use this script:
#! /bin/sh exec /local/grasp_tmp3/simonpj/ghc-BUILDS/working-alpha/ghc/driver/ghc \ -pgmC/local/grasp_tmp3/simonpj/ghc-BUILDS/working-hsc-prof/hsc \ -optCrts-i0.5 \ -optCrts-PT \ "$@"
`-ddump-rdr' reader output (earliest stuff in the compiler) `-ddump-rn' renamer output `-ddump-tc' typechecker output `-ddump-deriv' derived instances `-ddump-ds' desugarer output `-ddump-simpl' simplifer output (Core-to-Core passes) `-ddump-stranal' strictness analyser output `-ddump-occur-anal' `occurrence analysis' output `-ddump-spec' dump specialisation info `-ddump-stg' output of STG-to-STG passes `-ddump-absC' unflattened Abstract C `-ddump-flatC' flattened Abstract C `-ddump-realC' same as what goes to the C compiler `-ddump-asm' assembly language from the native-code generator
% ghc -noC -O -ddump-simpl -dverbose-simpl -dcore-lint Foo.hs
Let's do this by commenting an example. It's from doing
`-ddump-ds' on this code:
skip2 m = m : skip2 (m+2)
Before we jump in, a word about names of things. Within GHC, variables, type constructors, etc., are identified by their "Uniques." These are of the form `letter' plus `number' (both loosely interpreted). The `letter' gives some idea of where the Unique came from; e.g., `_' means "built-in type variable"; `t' means "from the typechecker"; `s' means "from the simplifier"; and so on. The `number' is printed fairly compactly in a `base-62' format, which everyone hates except me (WDP).
Remember, everything has a "Unique" and it is usually printed out when debugging, in some form or another. So here we go...
Desugared: Main.skip2{-r1L6-} :: _forall_ a$_4 =>{{Num a$_4}} -> a$_4 -> [a$_4] --# `r1L6' is the Unique for Main.skip2; --# `_4' is the Unique for the type-variable (template) `a' --# `{{Num a$_4}}' is a dictionary argument _NI_ --# `_NI_' means "no (pragmatic) information" yet; it will later --# evolve into the GHC_PRAGMA info that goes into interface files. Main.skip2{-r1L6-} = /\ _4 -> \ d.Num.t4Gt -> let { {- CoRec -} +.t4Hg :: _4 -> _4 -> _4 _NI_ +.t4Hg = (+{-r3JH-} _4) d.Num.t4Gt fromInt.t4GS :: Int{-2i-} -> _4 _NI_ fromInt.t4GS = (fromInt{-r3JX-} _4) d.Num.t4Gt --# The `+' class method (Unique: r3JH) selects the addition code --# from a `Num' dictionary (now an explicit lamba'd argument). --# Because Core is 2nd-order lambda-calculus, type applications --# and lambdas (/\) are explicit. So `+' is first applied to a --# type (`_4'), then to a dictionary, yielding the actual addition --# function that we will use subsequently... --# We play the exact same game with the (non-standard) class method --# `fromInt'. Unsurprisingly, the type `Int' is wired into the --# compiler. lit.t4Hb :: _4 _NI_ lit.t4Hb = let { ds.d4Qz :: Int{-2i-} _NI_ ds.d4Qz = I#! 2# } in fromInt.t4GS ds.d4Qz --# `I# 2#' is just the literal Int `2'; it reflects the fact that --# GHC defines `data Int = I# Int#', where Int# is the primitive --# unboxed type. (see relevant info about unboxed types elsewhere...) --# The `!' after `I#' indicates that this is a *saturated* --# application of the `I#' data constructor (i.e., not partially --# applied). skip2.t3Ja :: _4 -> [_4] _NI_ skip2.t3Ja = \ m.r1H4 -> let { ds.d4QQ :: [_4] _NI_ ds.d4QQ = let { ds.d4QY :: _4 _NI_ ds.d4QY = +.t4Hg m.r1H4 lit.t4Hb } in skip2.t3Ja ds.d4QY } in :! _4 m.r1H4 ds.d4QQ {- end CoRec -} } in skip2.t3Ja
("It's just a simple functional language" is an unregisterised trademark of Peyton Jones Enterprises, plc.)
Sometimes it is useful to make the connection between a source file and the command-line options it requires quite tight. For instance, if a (Glasgow) Haskell source file uses `casm's, the C back-end often needs to be told about which header files to include. Rather than maintaining the list of files the source depends on in a `Makefile' (using the `-#include' command-line option), it is possible to do this directly in the source file using the `OPTIONS' pragma :
{-# OPTIONS -#include "foo.h" #-} module X where ...
`OPTIONS' pragmas are only looked for at the top of your source files, upto the first (non-literate,non-empty) line not containing `OPTIONS'. Multiple `OPTIONS' pragmas are recognised. Note that your command shell does not get to the source file options, they are just included literally in the array of command-line arguments the compiler driver maintains internally, so you'll be desperately disappointed if you try to glob etc. inside `OPTIONS'.
NOTE: the contents of OPTIONS are prepended to the command-line options, so you *do* have the ability to override OPTIONS settings via the command line.
It is not recommended to move all the contents of your Makefiles into your source files, but in some circumstances, the `OPTIONS' pragma is the Right Thing. (If you use `-keep-hc-file-too' and have OPTION flags in your module, the OPTIONS will get put into the generated .hc file).
Currently, the compiler does not have proper support for dealing with mutually recursive modules:
module A where import B newtype A = A Int f :: B -> A f (B x) = A x -------- module B where import A data B = B !Int g :: A -> B g (A x) = B x
When compiling either module A and B, the compiler will try (in vain) to look for the interface file of the other. So, to get mutually recursive modules off the ground, you need to hand write an interface file for A or B, so as to break the loop. For the example at hand, the boot interface file for A would like the following:
_interface_ A 1 _exports_ A A(A) f; _declarations_ 1 newtype A = A PrelBase.Int ; 1 f _:_ B.B -> A.A ;;
To make sure you get the syntax right, tailoring an existing interface file is a Good Idea.
Note: This is all a temporary solution, a version of the compiler that handles mutually recursive properly without the manual construction of interface file, is in the works.
To make an executable program, the GHC system compiles your code and then links it with a non-trivial runtime system (RTS), which handles storage management, profiling, etc.
You have some control over the behaviour of the RTS, by giving special command-line arguments to your program.
When your Haskell program starts up, its RTS extracts
command-line arguments bracketed between `+RTS'
and `-RTS' as its own. For example:
% ./a.out -f +RTS -pT -S -RTS -h foo bar
The RTS will snaffle `-pT -S' for itself, and the remaining arguments `-f -h foo bar' will be handed to your program if/when it calls `System.getArgs'.
No `-RTS' option is required if the runtime-system options extend to the end of the command line, as in this example:
% hls -ltr /usr/etc +RTS -H5m
If you absolutely positively want all the rest of the options in a command line to go to the program (and not the RTS), use a `--RTS'.
As always, for RTS options that take `<size>'s: If the last character of `size' is a K or k, multiply by 1000; if an M or m, by 1,000,000; if a G or G, by 1,000,000,000. (And any wraparound in the counters is your fault!)
Giving a `+RTS -f' option will print out the RTS options actually available in your program (which vary, depending on how you compiled).
The most important RTS options are:
Besides the `-H' (set heap size) and `-S'/`-s' (GC stats) RTS options, there are several options to give you precise control over garbage collection.
The RTS options related to profiling are described in Section 7.3 How to control your profiled program at runtime; and those for concurrent/parallel stuff, in Section 11.2.7 RTS options for Concurrent/Parallel Haskell.
These RTS options might be used (a) to avoid a GHC bug, (b) to see "what's really happening", or (c) because you feel like it. Not recommended for everyday use!
GHC lets you exercise rudimentary control over the RTS settings for any given program, by compiling in a "hook" that is called by the run-time system. The RTS contains stub definitions for all these hooks, but by writing your own version and linking it on the GHC command line, you can override the defaults.
The function `defaultsHook' lets you change various RTS options. The commonest use for this is to give your program a default heap and/or stack size that is greater than the default. For example, to set `-H8m -K1m':
#include "rtsdefs.h" void defaultsHook (void) { RTSflags.GcFlags.stksSize = 1000002 / sizeof(W_); RTSflags.GcFlags.heapSize = 8000002 / sizeof(W_); }
Don't use powers of two for heap/stack sizes: these are more likely to interact badly with direct-mapped caches. The full set of flags is defined in `ghc/includes/RtsFlags.lh' the the GHC source tree.
You can also change the messages printed when the runtime system "blows up," e.g., on stack overflow. The hooks for these are as follows:
For example, here is the "hooks" code used by GHC itself:
#include <stdio.h> #define W_ unsigned long int #define I_ long int void ErrorHdrHook (FILE *where) { fprintf(where, "\n"); /* no "Fail: " */ } void OutOfHeapHook (W_ request_size, W_ heap_size) /* both sizes in bytes */ { fprintf(stderr, "GHC's heap exhausted;\nwhile trying to allocate %lu bytes in a %lu-byte heap;\nuse the `-H<size>' option to increase the total heap size.\n", request_size, heap_size); } void StackOverflowHook (I_ stack_size) /* in bytes */ { fprintf(stderr, "GHC stack-space overflow: current size %ld bytes.\nUse the `-K<size>' option to increase it.\n", stack_size); } void PatErrorHdrHook (FILE *where) { fprintf(where, "\n*** Pattern-matching error within GHC!\n\n This is a compiler bug; please report it to glasgow-haskell-bugs@dcs.gla.ac.uk.\n\nFail: "); } void PreTraceHook (FILE *where) { fprintf(where, "\n"); /* not "Trace On" */ } void PostTraceHook (FILE *where) { fprintf(where, "\n"); /* not "Trace Off" */ }
Please advise us of other "helpful hints" that should go here!
The key tool to use in making your Haskell program run faster are GHC's profiling facilities, described separately in section 7 Profiling Haskell programs. There is no substitute for finding where your program's time/space is really going, as opposed to where you imagine it is going.
Another point to bear in mind: By far the best way to improve a program's performance dramatically is to use better algorithms. Once profiling has thrown the spotlight on the guilty time-consumer(s), it may be better to re-think your program than to try all the tweaks listed below.
Another extremely efficient way to make your program snappy is to use library code that has been Seriously Tuned By Someone Else. You might be able to write a better quicksort than the one in the HBC library, but it will take you much longer than typing `import QSort'. (Incidentally, it doesn't hurt if the Someone Else is Lennart Augustsson.)
Please report any overly-slow GHC-compiled programs. The current definition of "overly-slow" is "the HBC-compiled version ran faster"...
hammeredLookup :: Ord key => [(key, value)] -> key -> valueIf it is heavily used on lists with `Widget' keys, you could specialise it as follows:
{-# SPECIALIZE hammeredLookup :: [(Widget, value)] -> Widget -> value #-}To get very fancy, you can also specify a named function to use for the specialised value, by adding `= blah', as in:
{-# SPECIALIZE hammeredLookup :: ...as before... = blah #-}It's Your Responsibility to make sure that `blah' really behaves as a specialised version of `hammeredLookup'!!! An example in which the `= blah' form will Win Big:
toDouble :: Real a => a -> Double toDouble = fromRational . toRational {-# SPECIALIZE toDouble :: Int -> Double = i2d #-} i2d (I# i) = D# (int2Double# i) -- uses Glasgow prim-op directlyThe `i2d' function is virtually one machine instruction; the default conversion -- via an intermediate `Rational' -- is obscenely expensive by comparison. By using the US spelling, your `SPECIALIZE' pragma will work with HBC, too. Note that HBC doesn't support the `= blah' form. A `SPECIALIZE' pragma for a function can be put anywhere its type signature could be put.
instance (Eq a) => Eq (Foo a) where { ... usual stuff ... } {-# SPECIALIZE instance Eq (Foo [(Int, Bar)] #-}Compatible with HBC, by the way. See also: overlapping instances, in Section 8.6 "HBC-ish" extensions implemented by GHC. They are to `SPECIALIZE instance' pragmas what `= blah' hacks are to `SPECIALIZE' (value) pragmas...
% egrep '^[a-z].*::.*=>' *.hi
f (Wibble x y) = ... # strict f arg = let { (Wibble x y) = arg } in ... # lazyThe former will result in far better code. A less contrived example shows the use of `cases' instead of `lets' to get stricter code (a good thing):
f (Wibble x y) # beautiful but slow = let (a1, b1, c1) = unpackFoo x (a2, b2, c2) = unpackFoo y in ... f (Wibble x y) # ugly, and proud of it = case (unpackFoo x) of { (a1, b1, c1) -> case (unpackFoo y) of { (a2, b2, c2) -> ... }}
key_function :: Int -> String -> (Bool, Double) #ifdef __GLASGOW_HASKELL__ {-# INLINE key_function #-} #endif(You don't need to do the C pre-processor carry-on unless you're going to stick the code through HBC -- it doesn't like `INLINE' pragmas.) The major effect of an `INLINE' pragma is to declare a function's "cost" to be very low. The normal unfolding machinery will then be very keen to inline it. An `INLINE' pragma for a function can be put anywhere its type signature could be put. `INLINE' pragmas are a particularly good idea for the `then'/`return' (or `bind'/`unit') functions in a monad. For example, in GHC's own `UniqueSupply' monad code, we have:
#ifdef __GLASGOW_HASKELL__ {-# INLINE thenUs #-} {-# INLINE returnUs #-} #endifGHC reserves the right to disallow any unfolding, even if you explicitly asked for one. That's because a function's body may become unexportable, because it mentions a non-exported value, to which any importing module would have no access. If you want to see why candidate unfoldings are rejected, use the `-freport-disallowed-unfoldings' option.
Decrease the "go-for-it" threshold for unfolding smallish expressions. Give a `-funfolding-use-threshold0' option for the extreme case. ("Only unfoldings with zero cost should proceed.")
(Note: I have not been too successful at producing code smaller than that which comes out with `-O'. WDP 94/12)
Avoid `Read'.
Use `strip' on your executables.
"I think I have a space leak..." Re-run your program with `+RTS -Sstderr', and remove all doubt! (You'll see the heap usage get bigger and bigger...) [Hmmm... this might be even easier with the `-F2s' RTS option; so... `./a.out +RTS -Sstderr -F2s'...]
Once again, the profiling facilities (section 7 Profiling Haskell programs) are the basic tool for demystifying the space behaviour of your program.
Strict functions are good to space usage, as they are for time, as discussed in the previous section. Strict functions get right down to business, rather than filling up the heap with closures (the system's notes to itself about how to evaluate something, should it eventually be required).
If you have a true blue "space leak" (your program keeps gobbling up
memory and never "lets go"), then 7 times out of 10 the problem is
related to a CAF (constant applicative form). Real people call
them "top-level values that aren't functions." Thus, for example:
x = (1 :: Int) f y = x ones = [ 1, (1 :: Float), .. ]
`x' and `ones' are CAFs; `f' is not.
The GHC garbage collectors are not clever about CAFs. The part of the heap reachable from a CAF is never collected. In the case of `ones' in the example above, it's disastrous. For this reason, the GHC "simplifier" tries hard to avoid creating CAFs, but it cannot subvert the will of a determined CAF-writing programmer (as in the case above).
Glasgow Haskell comes with a time and space profiling system. Its purpose is to help you improve your understanding of your program's execution behaviour, so you can improve it.
Any comments, suggestions and/or improvements you have to are welcome. Recommended "profiling tricks" would be especially cool!
The GHC approach to profiling is very simple: annotate the expressions you consider "interesting" with cost centre labels (strings); so, for example, you might have:
f x y = let output1 = _scc_ "Pass1" ( pass1 x ) output2 = _scc_ "Pass2" ( pass2 output1 y ) output3 = _scc_ "Pass3" ( pass3 (output2 `zip` [1 .. ]) ) in concat output3
The costs of the evaluating the expressions bound to `output1', `output2' and `output3' will be attributed to the "cost centres" `Pass1', `Pass2' and `Pass3', respectively.
The costs of evaluating other expressions, e.g., `concat output4', will be inherited by the scope which referenced the function `f'.
You can put in cost-centres via `_scc_' constructs by hand, as in the example above. Perfectly cool. That's probably what you would do if your program divided into obvious "passes" or "phases", or whatever.
If your program is large or you have no clue what might be gobbling all the time, you can get GHC to mark all functions with `_scc_' constructs, automagically. Add an `-auto' compilation flag to the usual `-prof' option.
Once you start homing in on the Guilty Suspects, you may well switch from automagically-inserted cost-centres to a few well-chosen ones of your own.
To use profiling, you must compile and run with special options. (We usually forget the "run" magic! -- Do as we say, not as we do...) Details follow.
If you're serious about this profiling game, you should probably read one or more of the Sansom/Peyton Jones papers about the GHC profiling system. Just visit the Glasgow FP Web page...
To make use of the cost centre profiling system all modules must be compiled and linked with the `-prof' option. Any `_scc_' constructs you've put in your source will spring to life.
Without a `-prof' option, your `_scc_'s are ignored; so you can compiled `_scc_'-laden code without changing it.
There are a few other profiling-related compilation options. Use them in addition to `-prof'. These do not have to be used consistently for all modules in a program.
In addition to the `-prof' option your system might be setup to enable you to compile and link with the `-prof-details' option instead. This enables additional detailed counts to be reported with the `-P' RTS option.
It isn't enough to compile your program for profiling with `-prof'!
When you run your profiled program, you must tell the runtime system (RTS) what you want to profile (e.g., time and/or space), and how you wish the collected data to be reported. You also may wish to set the sampling interval used in time profiling.
Executive summary: `./a.out +RTS -pT' produces a time profile in `a.out.prof'; `./a.out +RTS -hC' produces space-profiling info which can be mangled by `hp2ps' and viewed with `ghostview' (or equivalent).
Profiling runtime flags are passed to your program between the usual `+RTS' and `-RTS' options.
Heap (space) profiling uses hash tables. If these tables should fill the run will abort. The `-z<tbl><size>' option is used to increase the size of the relevant hash table (`C', `M', `G', `D' or `Y', defined as for <break-down> above). The actual size used is the next largest power of 2.
The heap profile can be restricted to particular closures of interest. The closures of interest can selected by the attached cost centre (module:label, module and group), closure category (description, type, and kind) and closure age using the following options:
The space occupied by a closure will be reported in the heap profile if the closure satisfies the following logical expression:
([-c] or [-m] or [-g]) and ([-d] or [-y] or [-k])
where a particular option is true if the closure (or its attached cost centre) is selected by the option (or the option is not specified).
When you run your profiled program with the `-p' RTS option , you get the following information about your "cost centres":
In addition you can use the `-P' RTS option to get the following additional information:
Finally if you built your program with `-prof-details' the `-P' RTS option will also produce the following information:
Utility programs which produce graphical profiles.
USAGE: `hp2ps' [flags] [<file>[`.stat']]
The program `hp2ps' converts a heap profile as produced by the `-h<break-down>' runtime option into a PostScript graph of the heap profile. By convention, the file to be processed by `hp2ps' has a `.hp' extension. The PostScript output is written to <file>`.ps'. If <file> is omitted entirely, then the program behaves as a filter.
`hp2ps' is distributed in `ghc/utils/hp2ps'. It was originally developed by Dave Wakeling as part of the HBC/LML heap profiler.
The flags are:
USAGE: `stat2resid' [<file>[`.stat'] [<outfile>]]
The program `stat2resid' converts a detailed garbage collection statistics file produced by the `-S' runtime option into a PostScript heap residency graph. The garbage collection statistics file can be produced without compiling your program for profiling.
By convention, the file to be processed by `stat2resid' has a `.stat' extension. If the <outfile> is not specified the PostScript will be written to <file>`.resid.ps'. If <file> is omitted entirely, then the program behaves as a filter.
The plot can not be produced from the statistics file for a generational collector, though a suitable stats file can be produced using the `-F2s' runtime option when the program has been compiled for generational garbage collection (the default).
`stat2resid' is distributed in `ghc/utils/stat2resid'.
As with all known Haskell systems, GHC implements some extensions to the language. To use them, you'll need to give a `-fglasgow-exts' option.
Virtually all of the Glasgow extensions serve to give you access to 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!
Executive summary of our extensions:
Before you get too carried away working at the lowest level (e.g., sloshing `MutableByteArray#'s around your program), you may wish to check if there are system libraries that provide a "Haskellised veneer" over the features you want. See Section 10 System libraries.
Section 9 The GHC prelude and libraries is the definitive guide for many of the low-level facilities in GHC.
These types correspond to the "raw machine" types you would use in C: `Int#' (long int), `Double#' (double), `Addr#' (void *), etc. The primitive operations (PrimOps) on these types are what you might expect; e.g., `(+#)' is addition on `Int#'s, and is the machine-addition that we all know and love -- usually one instruction.
A numerically-intensive program using unboxed types can go a lot faster than its "standard" counterpart -- we saw a threefold speedup on one example.
Please see Section 9.2 The module `GHC': really primitive stuff for the details of unboxed types and the operations on them.
This monad underlies our implementation of arrays, mutable and immutable, and our implementation of I/O, including "C calls".
You probably won't use the monad directly, but you might use all those other things!
More information on the state-related types can be found in the elsewhere, Section 9 The GHC prelude and libraries.
GHC knows about quite a few flavours of Large Swathes of Bytes.
First, GHC distinguishes between primitive arrays of (boxed) Haskell objects (type `Array# obj') and primitive arrays of bytes (type `ByteArray#').
Second, it distinguishes between...
The libraries section give more details on all these "primitive array" types and the operations on them, Section 9 The GHC prelude and libraries.
Normally, the GHC runtime system begins things by called an internal function
mainIO :: IO ()
which, in turn, fires up your `Main.main'. The standard definition of `mainIO' looks like this:
mainIO = catch Main.main (\err -> error ("I/O error: " ++ showsPrec 0 err "\n"))
that is, all it does is run `Main.main', catching any I/O errors that occur and displaying them on standard error before exiting the program.
To subvert the above process, you need only provide a `mainIO' of your own (in a module named `GHCmain').
Here's a little example, stolen from Alastair Reid:
module GHCmain ( mainIO ) where import GlaExts mainIO :: IO () mainIO = do sleep 5 _ccall_ printf "%d\n" (14::Int) sleep :: Int -> IO () sleep t = _ccall_ sleep t
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. It will then be quite easy to update later on.
WARNING AS OF 2.03: Yes, the `_ccall_' stuff probably will
change, to something better, of course! One step in that direction
is Green Card, a foreign function interface pre-processor for Haskell
("Glasgow" Haskell in particular) -- check out
ftp://ftp.dcs.gla.ac.uk/pub/haskell/glasgow/green-card.ANNOUNCE ftp://ftp.dcs.gla.ac.uk/pub/haskell/glasgow/green-card-src.tar.gz
The simplest way to use a simple C function
double fooC( FILE *in, char c, int i, double d, unsigned int u )
is to provide a Haskell wrapper:
fooH :: Char -> Int -> Double -> Word -> IO Double fooH c i d w = _ccall_ fooC ("stdin"::Addr) c i d w
The function `fooH' will unbox all of its arguments, call the C function `fooC' and box the corresponding arguments.
One of the annoyances about `_ccall_'s is when the C types don't quite match the Haskell compiler's ideas. For this, the `_casm_' variant may be just the ticket (NB: no chance of such code going through a native-code generator):
oldGetEnv name = _casm_ "%r = getenv((char *) %0);" name >>= \ litstring@(A# str#) -> return ( if (litstring == "NULL") then Left ("Fail:oldGetEnv:"++name) else Right (unpackCString# str#) )
The first literal-literal argument to a `_casm_' is like a `printf' format: `%r' is replaced with the "result," `%0'--`%n-1' are replaced with the 1st--nth arguments. As you can see above, it is an easy way to do simple C casting. Everything said about `_ccall_' goes for `_casm_' as well.
When generating C (using the `-fvia-C' directive), one can assist the C compiler in detecting type errors by using the `-#include' directive to provide `.h' files containing function headers.
typedef unsigned long *StgForeignObj; typedef long StgInt; void initialiseEFS (StgInt size); StgInt terminateEFS (void); StgForeignObj emptyEFS(void); StgForeignObj updateEFS (StgForeignObj a, StgInt i, StgInt x); StgInt lookupEFS (StgForeignObj a, StgInt i);
You can find appropriate definitions for `StgInt', `StgForeignObj', etc using `gcc' on your architecture by consulting `ghc/includes/StgTypes.lh'. The following table summarises the relationship between Haskell types and C types.
C type name Haskell Type ------------------------------------------------------ `StgChar' `Char#' `StgInt' `Int#' `StgWord' `Word#' `StgAddr' `Addr#' `StgFloat' `Float#' `StgDouble' `Double#' `StgArray' `Array#' `StgByteArray' `ByteArray#' `StgArray' `MutableArray#' `StgByteArray' `MutableByteArray#' `StgStablePtr' `StablePtr#' `StgForeignObj' `ForeignObj#'
Note that this approach is only essential for returning `float's (or if `sizeof(int) != sizeof(int *)' on your architecture) but is a Good Thing for anyone who cares about writing solid code. You're crazy not to do it.
The arguments of a `_ccall_' are automatically unboxed before the call. There are two reasons why this is usually the Right Thing to do:
It is possible to subvert the unboxing process by creating a "stable
pointer" to a value and passing the stable pointer instead. For example, to
pass/return an integer lazily to C functions `storeC' and
`fetchC', one might write:
storeH :: Int -> IO () storeH x = makeStablePtr x >>= \ stable_x -> _ccall_ storeC stable_x fetchH :: IO Int fetchH x = _ccall_ fetchC >>= \ stable_x -> deRefStablePtr stable_x >>= \ x -> freeStablePtr stable_x >> return x
The garbage collector will refrain from throwing a stable pointer away until you explicitly call one of the following from C or Haskell.
void freeStablePointer( StgStablePtr stablePtrToToss ) freeStablePtr :: StablePtr a -> IO ()
As with the use of `free' in C programs, GREAT CARE SHOULD BE EXERCISED to ensure these functions are called at the right time: too early and you get dangling references (and, if you're lucky, an error message from the runtime system); too late and you get space leaks.
And to force evaluation of the argument within `fooC', one would call one of the following C functions (according to type of argument).
void performIO ( StgStablePtr stableIndex /* StablePtr s (IO ()) */ ); StgInt enterInt ( StgStablePtr stableIndex /* StablePtr s Int */ ); StgFloat enterFloat ( StgStablePtr stableIndex /* StablePtr s Float */ );
Note Bene: `_ccall_GC_' must be used if any of these functions are used.
There are two types that `ghc' programs can use to reference (heap-allocated) objects outside the Haskell world: `Addr' and `ForeignObj'.
If you use `Addr', it is up to you to the programmer to arrange allocation and deallocation of the objects.
If you use `ForeignObj', `ghc''s garbage collector will call upon the user-supplied finaliser function to free the object when the Haskell world no longer can access the object. (An object is associated with a finaliser function when the abstract Haskell type `ForeignObj' is created). The finaliser function is expressed in C, and is passed as argument the object:
void foreignFinaliser ( StgForeignObj fo )
when the Haskell world can no longer access the object. Since `ForeignObj's only get released when a garbage collection occurs, we provide ways of triggering a garbage collection from within C and from within Haskell.
void StgPerformGarbageCollection() performGC :: IO ()
More information is provided on the programmers' interface to `ForeignObj' can be found in Section 9.4.5 Foreign objects.
The `_ccall_' construct is part of the `IO' monad because 9 out of 10 uses will be to call imperative functions with side effects such as `printf'. Use of the monad ensures that these operations happen in a predictable order in spite of laziness and compiler optimisations.
To avoid having to be in the monad to call a C function, it is possible to use `unsafePerformIO', which is available from the `IOExts' module. There are three situations where one might like to call a C function from outside the IO world:
atan2d :: Double -> Double -> Double atan2d y x = unsafePerformIO (_ccall_ atan2d y x) sincosd :: Double -> (Double, Double) sincosd x = unsafePerformIO $ do da <- newDoubleArray (0, 1) _casm_ "sincosd( %0, &((double *)%1[0]), &((double *)%1[1]) );" x da s <- readDoubleArray da 0 c <- readDoubleArray da 1 return (s, c)
empty :: EFS x update :: EFS x -> Int -> x -> EFS x lookup :: EFS a -> Int -> a empty = unsafePerformIO (_ccall_ emptyEFS) update a i x = unsafePerformIO $ makeStablePtr x >>= \ stable_x -> _ccall_ updateEFS a i stable_x lookup a i = unsafePerformIO $ _ccall_ lookupEFS a i >>= \ stable_x -> deRefStablePtr stable_xYou will almost always want to use `ForeignObj's with this.
trace :: String -> a -> a trace string expr = unsafePerformIO ( ((_ccall_ PreTraceHook sTDERR{-msg-}):: IO ()) >> fputs sTDERR string >> ((_ccall_ PostTraceHook sTDERR{-msg-}):: IO ()) >> return expr ) where sTDERR = ("stderr" :: Addr)(This kind of use is not highly recommended -- it is only really useful in debugging code.)
And some advice, too.
f x = _ccall_ foo xis not good enough, because the compiler can't work out what type `x' is, nor what type the `_ccall_' returns. You have to write, say:
f :: Int -> IO Double f x = _ccall_ foo xThis table summarises the standard instances of these classes.
Type CCallable CReturnable Which is probably... ---------------------------------------------------------------------------------------- `Char' Yes Yes `unsigned char' `Int' Yes Yes `long int' `Word' Yes Yes `unsigned long int' `Addr' Yes Yes `char *' `Float' Yes Yes `float' `Double' Yes Yes `double' `()' No Yes `void' `[Char]' Yes No `char *' (null-terminated) `Array' Yes No `unsigned long *' `ByteArray' Yes No `unsigned long *' `MutableArray' Yes No `unsigned long *' `MutableByteArray' Yes No `unsigned long *' `State' Yes Yes nothing! `StablePtr' Yes Yes `unsigned long *' `ForeignObjs' Yes Yes see laterThe brave and careful programmer can add their own instances of these classes for the following types:
Int Double data XDisplay = XDisplay Addr# data EFS a = EFS# ForeignObj#
instance CCallable (EFS a) instance CReturnable (EFS a)
data MyVoid = MyVoid instance CReturnable MyVoid
This document describes GHC's prelude and libraries. The basic story is that of the Haskell 1.4 Report and Libraries document (which we do not reproduce here), but this document describes in addition:
In addition to the GHC prelude libraries, GHC comes with a number of system libraries, which are presented in Section 10 System libraries.
Probably only of interest to implementors...
The prelude libraries are organised into the following three groups, each of which is kept in a separate sub-directory of GHC's source `lib/' directory:
The `...Base' modules generally export representation information that is hidden from the public interface. For example the module `STBase' exports the type `ST' including its representation, whereas the module `ST' exports `ST' abstractly.
None of these modules are involved in any mutual recursion, with the sole exception that many modules import `Error.error'.
This section defines all the types which are primitive in Glasgow Haskell, and the operations provided for them.
A primitive type is one which cannot be defined in Haskell, and which is therefore built into the language and compiler. Primitive types are always unboxed; that is, a value of primitive type cannot be bottom.
Primitive values are often represented by a simple bit-pattern, such as `Int#', `Float#', `Double#'. But this is not necessarily the case: a primitive value might be represented by a pointer to a heap-allocated object. Examples include `Array#', the type of primitive arrays. You might think this odd: doesn't being heap-allocated mean that it has a box? No, it does not. A primitive array is heap-allocated because it is too big a value to fit in a register, and would be too expensive to copy around; in a sense, 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.
This section also describes a few non-primitive types, which are needed to express the result types of some primitive operations.
There are the following obvious primitive types:
type Char# type Int# -- see also Word# and Addr#, later type Float# type Double#
If you really want to know their exact equivalents in C, see `ghc/includes/StgTypes.lh' in the GHC source tree.
Literals for these types may be written as follows:
1# an Int# 1.2# a Float# 1.34## a Double# 'a'# a Char#; for weird characters, use '\o<octal>'# "a"# an Addr# (a `char *')
{>,>=,==,/=,<,<=}# :: Int# -> Int# -> Bool {gt,ge,eq,ne,lt,le}Char# :: Char# -> Char# -> Bool -- ditto for Word#, Float#, Double#, and Addr#
ord# :: Char# -> Int# chr# :: Int# -> Char#
{+,-,*,quotInt,remInt}# :: Int# -> Int# -> Int# negateInt# :: Int# -> Int# iShiftL#, iShiftRA#, iShiftRL# :: Int# -> Int# -> Int# -- shift left, right arithmetic, right logical
Note: No error/overflow checking!
{plus,minus,times,divide}Double# :: Double# -> Double# -> Double# negateDouble# :: Double# -> Double# float2Int# :: Double# -> Int# -- just a cast, no checking! int2Double# :: Int# -> Double# expDouble# :: Double# -> Double# logDouble# :: Double# -> Double# sqrtDouble# :: Double# -> Double# sinDouble# :: Double# -> Double# cosDouble# :: Double# -> Double# tanDouble# :: Double# -> Double# asinDouble# :: Double# -> Double# acosDouble# :: Double# -> Double# atanDouble# :: Double# -> Double# sinhDouble# :: Double# -> Double# coshDouble# :: Double# -> Double# tanhDouble# :: Double# -> Double# powerDouble# :: Double# -> Double# -> Double#
There's an exactly-matching set of unboxed-`Float' ops; replace `Double#' with `Float#' in the list above. There are two coercion functions for `Float#'/`Double#':
float2Double# :: Float# -> Double# double2Float# :: Double# -> Float#
The primitive versions of `encodeDouble'/`decodeDouble':
encodeDouble# :: Int# -> Int# -> ByteArray# -- Integer mantissa -> Int# -- Int exponent -> Double# decodeDouble# :: Double# -> PrelNum.ReturnIntAndGMP
(And the same for `Float#'s.)
We implement `Integers' (arbitrary-precision integers) using the GNU multiple-precision (GMP) package (version 1.3.2).
Note: some of this might change when we upgrade to using GMP 2.x.
The data type for `Integer' must mirror that for `MP_INT' in `gmp.h' (see `gmp.info' in `ghc/includes/runtime/gmp'). It comes out as:
data Integer = J# Int# Int# ByteArray#
So, `Integer' is really just a "pairing" type for a particular collection of primitive types.
The operations in the GMP return other combinations of GMP-plus-something, so we need "pairing" types for those, too:
data Return2GMPs = Return2GMPs Int# Int# ByteArray# Int# Int# ByteArray# data ReturnIntAndGMP = ReturnIntAndGMP Int# Int# Int# ByteArray# -- ????? something to return a string of bytes (in the heap?)
The primitive ops to support `Integers' use the "pieces" of the representation, and are as follows:
negateInteger# :: Int# -> Int# -> ByteArray# -> Integer {plus,minus,times}Integer# :: Int# -> Int# -> ByteArray# -> Int# -> Int# -> ByteArray# -> Integer cmpInteger# :: Int# -> Int# -> ByteArray# -> Int# -> Int# -> ByteArray# -> Int# -- -1 for <; 0 for ==; +1 for > divModInteger#, quotRemInteger# :: Int# -> Int# -> ByteArray# -> Int# -> Int# -> ByteArray# -> PrelNum.Return2GMPs integer2Int# :: Int# -> Int# -> ByteArray# -> Int# int2Integer# :: Int# -> Integer -- NB: no error-checking on these two! word2Integer# :: Word# -> Integer addr2Integer# :: Addr# -> Integer -- the Addr# is taken to be a `char *' string -- to be converted into an Integer.
A `Word#' is used for bit-twiddling operations. It is the same size as an `Int#', but has no sign nor any arithmetic operations.
type Word# -- Same size/etc as Int# but *unsigned* type Addr# -- A pointer from outside the "Haskell world" (from C, probably); -- described under "arrays"
`Word#'s and `Addr#'s have the usual comparison operations. Other unboxed-`Word' ops (bit-twiddling and coercions):
and#, or#, xor# :: Word# -> Word# -> Word# -- standard bit ops. quotWord#, remWord# :: Word# -> Word# -> Word# -- word (i.e. unsigned) versions are different from int -- versions, so we have to provide these explicitly. not# :: Word# -> Word# shiftL#, shiftRA#, shiftRL# :: Word# -> Int# -> Word# -- shift left, right arithmetic, right logical int2Word# :: Int# -> Word# -- just a cast, really word2Int# :: Word# -> Int#
Unboxed-`Addr' ops (C casts, really):
int2Addr# :: Int# -> Addr# addr2Int# :: Addr# -> Int#
The casts between `Int#', `Word#' and `Addr#' correspond to null operations at the machine level, but are required to keep the Haskell type checker happy.
Operations for indexing off of C pointers (`Addr#'s) to snatch values are listed under "arrays".
The type `Array# elt' is the type of primitive, unboxed arrays of values of type `elt'.
type Array# elt
`Array#' is more primitive than a Haskell array -- indeed, the Haskell `Array' interface is implemented using `Array#' -- in that an `Array#' is indexed only by `Int#'s, starting at zero. It is also more primitive by virtue of being unboxed. That doesn't mean that it isn't a heap-allocated object -- of course, it is. Rather, being unboxed means that it is represented by a pointer to the array itself, and not to a thunk which will evaluate to the array (or to bottom). The components of an `Array#' are themselves boxed.
The type `ByteArray#' is similar to `Array#', except that it contains just a string of (non-pointer) bytes.
type ByteArray#
Arrays of these types are useful when a Haskell program wishes to construct a value to pass to a C procedure. It is also possible to use them to build (say) arrays of unboxed characters for internal use in a Haskell program. Given these uses, `ByteArray#' is deliberately a bit vague about the type of its components. Operations are provided to extract values of type `Char#', `Int#', `Float#', `Double#', and `Addr#' from arbitrary offsets within a `ByteArray#'. (For type `Foo#', the ith offset gets you the ith `Foo#', not the `Foo#' at byte-position i. Mumble.) (If you want a `Word#', grab an `Int#', then coerce it.)
Lastly, we have static byte-arrays, of type `Addr#' [mentioned previously]. (Remember the duality between arrays and pointers in C.) Arrays of this types are represented by a pointer to an array in the world outside Haskell, so this pointer is not followed by the garbage collector. In other respects they are just like `ByteArray#'. They are only needed in order to pass values from C to Haskell.
Primitive arrays are linear, and indexed starting at zero.
The size and indices of a `ByteArray#', `Addr#', and `MutableByteArray#' are all in bytes. It's up to the program to calculate the correct byte offset from the start of the array. This allows a `ByteArray#' to contain a mixture of values of different type, which is often needed when preparing data for and unpicking results from C. (Umm... not true of indices... WDP 95/09)
Should we provide some `sizeOfDouble#' constants?
Out-of-range errors on indexing should be caught by the code which uses the primitive operation; the primitive operations themselves do not check for out-of-range indexes. The intention is that the primitive ops compile to one machine instruction or thereabouts.
We use the terms "reading" and "writing" to refer to accessing mutable arrays (see Section 9.2.13 Mutable arrays), and "indexing" to refer to reading a value from an immutable array.
Immutable byte arrays are straightforward to index (all indices in bytes):
indexCharArray# :: ByteArray# -> Int# -> Char# indexIntArray# :: ByteArray# -> Int# -> Int# indexAddrArray# :: ByteArray# -> Int# -> Addr# indexFloatArray# :: ByteArray# -> Int# -> Float# indexDoubleArray# :: ByteArray# -> Int# -> Double# indexCharOffAddr# :: Addr# -> Int# -> Char# indexIntOffAddr# :: Addr# -> Int# -> Int# indexFloatOffAddr# :: Addr# -> Int# -> Float# indexDoubleOffAddr# :: Addr# -> Int# -> Double# indexAddrOffAddr# :: Addr# -> Int# -> Addr# -- Get an Addr# from an Addr# offset
The last of these, `indexAddrOffAddr#', extracts an `Addr#' using an offset from another `Addr#', thereby providing the ability to follow a chain of C pointers.
Something a bit more interesting goes on when indexing arrays of boxed
objects, because the result is simply the boxed object. So presumably
it should be entered -- we never usually return an unevaluated
object! This is a pain: primitive ops aren't supposed to do
complicated things like enter objects. The current solution is to
return a lifted value, but I don't like it!
indexArray# :: Array# elt -> Int# -> PrelBase.Lift elt -- Yuk!
The primitive type `State#' represents the state of a state transformer.
It is parameterised on the desired type of state, which serves to keep
states from distinct threads distinct from one another. But the only
effect of this parameterisation is in the type system: all values of type
`State#' are represented in the same way. Indeed, they are all
represented by nothing at all! The code generator "knows" to generate no
code, and allocate no registers etc, for primitive states.
type State# s
The type `GHC.RealWorld' is truly opaque: there are no values defined of this type, and no operations over it. It is "primitive" in that sense -- but it is not unboxed! Its only role in life is to be the type which distinguishes the `IO' state transformer.
data RealWorld
A single, primitive, value of type `State# RealWorld' is provided.
realWorld# :: State# GHC.RealWorld
(Note: in the compiler, not a `PrimOp'; just a mucho magic `Id'. Exported from `GHC', though).
This subsection defines some types which, while they aren't quite primitive because we can define them in Haskell, are very nearly so. They define constructors which pair a primitive state with a value of each primitive type. They are required to express the result type of the primitive operations in the state monad.
data StateAndPtr# s elt = StateAndPtr# (State# s) elt data StateAndChar# s = StateAndChar# (State# s) Char# data StateAndInt# s = StateAndInt# (State# s) Int# data StateAndWord# s = StateAndWord# (State# s) Word# data StateAndFloat# s = StateAndFloat# (State# s) Float# data StateAndDouble# s = StateAndDouble# (State# s) Double# data StateAndAddr# s = StateAndAddr# (State# s) Addr# data StateAndStablePtr# s a = StateAndStablePtr# (State# s) (StablePtr# a) data StateAndForeignObj# s = StateAndForeignObj# (State# s) ForeignObj# data StateAndSynchVar# s a = StateAndSynchVar# (State# s) (SynchVar# a) data StateAndArray# s elt = StateAndArray# (State# s) (Array# elt) data StateAndMutableArray# s elt = StateAndMutableArray# (State# s) (MutableArray# s elt) data StateAndByteArray# s = StateAndByteArray# (State# s) ByteArray# data StateAndMutableByteArray# s = StateAndMutableByteArray# (State# s) (MutableByteArray# s)
Hideous.
Corresponding to `Array#' and `ByteArray#', we have the types of
mutable versions of each. In each case, the representation is a
pointer to a suitable block of (mutable) heap-allocated storage.
type MutableArray# s elt type MutableByteArray# s
Mutable arrays can be allocated. Only pointer-arrays are initialised; arrays of non-pointers are filled in by "user code" rather than by the array-allocation primitive. Reason: only the pointer case has to worry about GC striking with a partly-initialised array.
newArray# :: Int# -> elt -> State# s -> StateAndMutableArray# s elt newCharArray# :: Int# -> State# s -> StateAndMutableByteArray# s newIntArray# :: Int# -> State# s -> StateAndMutableByteArray# s newAddrArray# :: Int# -> State# s -> StateAndMutableByteArray# s newFloatArray# :: Int# -> State# s -> StateAndMutableByteArray# s newDoubleArray# :: Int# -> State# s -> StateAndMutableByteArray# s
The size of a `ByteArray#' is given in bytes.
readArray# :: MutableArray# s elt -> Int# -> State# s -> StateAndPtr# s elt readCharArray# :: MutableByteArray# s -> Int# -> State# s -> StateAndChar# s readIntArray# :: MutableByteArray# s -> Int# -> State# s -> StateAndInt# s readAddrArray# :: MutableByteArray# s -> Int# -> State# s -> StateAndAddr# s readFloatArray# :: MutableByteArray# s -> Int# -> State# s -> StateAndFloat# s readDoubleArray# :: MutableByteArray# s -> Int# -> State# s -> StateAndDouble# s writeArray# :: MutableArray# s elt -> Int# -> elt -> State# s -> State# s writeCharArray# :: MutableByteArray# s -> Int# -> Char# -> State# s -> State# s writeIntArray# :: MutableByteArray# s -> Int# -> Int# -> State# s -> State# s writeAddrArray# :: MutableByteArray# s -> Int# -> Addr# -> State# s -> State# s writeFloatArray# :: MutableByteArray# s -> Int# -> Float# -> State# s -> State# s writeDoubleArray# :: MutableByteArray# s -> Int# -> Double# -> State# s -> State# s
One can take "equality" of mutable arrays. What is compared is the name or reference to the mutable array, not its contents.
sameMutableArray# :: MutableArray# s elt -> MutableArray# s elt -> Bool sameMutableByteArray# :: MutableByteArray# s -> MutableByteArray# s -> Bool
Only unsafe-freeze has a primitive. (Safe freeze is done directly in Haskell by copying the array and then using `unsafeFreeze'.)
unsafeFreezeArray# :: MutableArray# s elt -> State# s -> StateAndArray# s elt unsafeFreezeByteArray# :: MutableByteArray# s -> State# s -> StateAndByteArray# s
A stable pointer is a name for a Haskell object which can be passed to the external world. It is "stable" in the sense that the name does not change when the Haskell garbage collector runs -- in contrast to the address of the object which may well change.
The stable pointer type is parameterised by the type of the thing
which is named.
type StablePtr# a
A stable pointer is represented by an index into the (static) `StablePointerTable'. The Haskell garbage collector treats the `StablePointerTable' as a source of roots for GC.
The `makeStablePointer' function converts a value into a stable pointer. It is part of the `IO' monad, because we want to be sure we don't allocate one twice by accident, and then only free one of the copies.
makeStablePointer# :: a -> State# RealWorld -> StateAndStablePtr# RealWorld a freeStablePointer# :: StablePtr# a -> State# RealWorld -> State# RealWorld deRefStablePointer# :: StablePtr# a -> State# RealWorld -> StateAndPtr RealWorld a
There is also a C procedure `FreeStablePtr' which frees a stable pointer.
A `ForeignObj#' is a reference to an object outside the Haskell world (i.e., from the C world, or a reference to an object on another machine completely.), where the Haskell world has been told "Let me know when you're finished with this ...".
type ForeignObj#
GHC provides two primitives on `ForeignObj#':
makeForeignObj# :: Addr# -- foreign reference -> Addr# -- pointer to finalisation routine -> StateAndForeignObj# RealWorld ForeignObj# writeForeignObj :: ForeignObj# -- foreign object -> Addr# -- datum -> State# RealWorld -> State# RealWorld
The module `Foreign' (Section 9.4.5 Foreign objects) provides a more programmer-friendly interface to foreign objects.
Synchronising variables are the primitive type used to implement Concurrent Haskell's MVars (see the Concurrent Haskell paper for the operational behaviour of these operations).
type SynchVar# s elt -- primitive newSynchVar#:: State# s -> StateAndSynchVar# s elt takeMVar# :: SynchVar# s elt -> State# s -> StateAndPtr# s elt putMVar# :: SynchVar# s elt -> State# s -> State# s
ToDo: say something It's used in the unfolding for `par'.
The `errorIO#' primitive takes an argument much like `IO'. It aborts execution of the current program, and continues instead by performing the given `IO'-like value on the current state of the world.
errorIO# :: (State# RealWorld# -> a -> a
This library provides support for both lazy and strict state threads. In addition to the monad ST, it also provides mutable variables STRef and mutable arrays STArray. As the name suggests, the monad ST instance is lazy.
module LazyST( module LazyST, module Monad ) where import Monad data ST s a -- abstract type runST :: forall a. (forall s. ST s a) -> a returnST :: a -> ST s a thenLazyST :: ST s a -> (a -> ST s b) -> ST s b thenStrictST :: ST s a -> (a -> ST s b) -> ST s b fixST :: (a -> ST s a) -> ST s a unsafeInterleaveST :: ST s a -> ST s a instance Functor (ST s) instance Monad (ST s) data STRef s a -- mutable variables in state thread s -- containing values of type a. newSTRef :: a -> ST s (STRef s a) readSTRef :: STRef s a -> ST s a writeSTRef :: STRef s a -> a -> ST s () instance Eq (STRef s a) data STArray s ix elt -- mutable arrays in state thread s -- indexed by values of type ix -- containing values of type a. newSTArray :: Ix ix => (ix,ix) -> elt -> ST s (STArray s ix elt) boundsSTArray :: Ix ix => STArray s ix elt -> (ix, ix) readSTArray :: Ix ix => STArray s ix elt -> ix -> ST s elt writeSTArray :: Ix ix => STArray s ix elt -> ix -> elt -> ST s () thawSTArray :: Ix ix => Array ix elt -> ST s (STArray s ix elt) freezeSTArray :: Ix ix => STArray s ix elt -> ST s (Array ix elt) unsafeFreezeSTArray :: Ix ix => STArray s ix elt -> ST s (Array ix elt) instance Eq (STArray s ix elt)
Notes:
This library is identical to LazyST except that the ST monad instance is strict. Most programmers use the strict instance to avoid the space leaks associated with the lazy instance.
This library provides the following extensions to the IO monad:
module IOExts where fixIO :: (a -> IO a) -> IO a unsafePerformIO :: IO a -> a unsafeInterleaveIO :: IO a -> IO a data IORef a -- mutable variables containing values of type a newIORef :: a -> IO (IORef a) readIORef :: IORef a -> IO a writeIORef :: IORef a -> a -> IO () instance Eq (IORef a) data IOArray ix elt -- mutable arrays indexed by values of type ix -- containing values of type a. newIOArray :: Ix ix => (ix,ix) -> elt -> IO (IOArray ix elt) boundsIOArray :: Ix ix => IOArray ix elt -> (ix, ix) readIOArray :: Ix ix => IOArray ix elt -> ix -> IO elt writeIOArray :: Ix ix => IOArray ix elt -> ix -> elt -> IO () freezeIOArray :: Ix ix => IOArray ix elt -> IO (Array ix elt) instance Eq (IOArray ix elt) trace :: String -> a -> a performGC :: IO ()
This library defines bitwise operations for signed and unsigned ints.
module Bits where infixl 8 `shift`, `rotate` infixl 7 .&. infixl 6 `xor` infixl 5 .|. class Bits a where (.&.), (.|.), xor :: a -> a -> a complement :: a -> a shift :: a -> Int -> a rotate :: a -> Int -> a bit :: Int -> a setBit :: a -> Int -> a clearBit :: a -> Int -> a complementBit :: a -> Int -> a testBit :: a -> Int -> Bool bitSize :: a -> Int isSigned :: a -> Bool shiftL, shiftR :: Bits a => a -> Int -> a rotateL, rotateR :: Bits a => a -> Int -> a shiftL a i = shift a i shiftR a i = shift a (-i) rotateL a i = rotate a i rotateR a i = rotate a (-i)
Notes:
This library provides unsigned integers of various sizes. The types supported are as follows:
type number of bits ---------------------- Word8 8 Word16 16 Word32 32 Word64 64 ----------------------
For each type {@it W} above, we provide the following functions and instances. The type {@it I} refers to the signed integer type of the same size.
data W -- Unsigned Ints instance Eq W instance Ord W instance Show W instance Read W instance Bounded W instance Num W instance Real W instance Integral W instance Enum W instance Ix W instance Bits W
Plus
word8ToWord32 :: Word8 -> Word32 word32ToWord8 :: Word32 -> Word8 word16ToWord32 :: Word16 -> Word32 word32ToWord16 :: Word32 -> Word16 word8ToInt :: Word8 -> Int intToWord8 :: Int -> Word8 word16ToInt :: Word16 -> Int intToWord16 :: Int -> Word16 word32ToInt :: Word32 -> Int intToWord32 :: Int -> Word32
Notes:
Hugs only provides Eq, Ord, Read and Show instances for Word64 at the moment.
This library provides signed integers of various sizes. The types supported are as follows:
type number of bits --------------------- Int8 8 Int16 16 Int32 32 Int64 64 ---------------------
For each type {@it I} above, we provide the following instances.
data I -- Signed Ints iToInt :: I -> Int -- not provided for Int64 intToi :: Int -> I -- not provided for Int64 instance Eq I instance Ord I instance Show I instance Read I instance Bounded I instance Num I instance Real I instance Integral I instance Enum I instance Ix I instance Bits I
Plus
int8ToInt :: Int8 -> Int intToInt8 :: Int -> Int8 int16ToInt :: Int16 -> Int intToInt16 :: Int -> Int16 int32ToInt :: Int32 -> Int intToInt32 :: Int -> Int32
This library provides machine addresses and is primarily intended for use in creating foreign function interfaces using GreenCard.
module Addr where data Addr -- Address type instance Eq Addr nullAddr :: Addr plusAddr :: Addr -> Int -> Addr -- read value out of _immutable_ memory indexCharOffAddr :: Addr -> Int -> Char indexIntOffAddr :: Addr -> Int -> Int -- should we drop this? indexAddrOffAddr :: Addr -> Int -> Addr indexFloatOffAddr :: Addr -> Int -> Float indexDoubleOffAddr :: Addr -> Int -> Double indexWord8OffAddr :: Addr -> Int -> Word8 indexWord16OffAddr :: Addr -> Int -> Word16 indexWord32OffAddr :: Addr -> Int -> Word32 indexWord64OffAddr :: Addr -> Int -> Word64 indexInt8OffAddr :: Addr -> Int -> Int8 indexInt16OffAddr :: Addr -> Int -> Int16 indexInt32OffAddr :: Addr -> Int -> Int32 indexInt64OffAddr :: Addr -> Int -> Int64 -- read value out of mutable memory readCharOffAddr :: Addr -> Int -> IO Char readIntOffAddr :: Addr -> Int -> IO Int -- should we drop this? readAddrOffAddr :: Addr -> Int -> IO Addr readFloatOffAddr :: Addr -> Int -> IO Float readDoubleOffAddr :: Addr -> Int -> IO Double readWord8OffAddr :: Addr -> Int -> IO Word8 readWord16OffAddr :: Addr -> Int -> IO Word16 readWord32OffAddr :: Addr -> Int -> IO Word32 readWord64OffAddr :: Addr -> Int -> IO Word64 readInt8OffAddr :: Addr -> Int -> IO Int8 readInt16OffAddr :: Addr -> Int -> IO Int16 readInt32OffAddr :: Addr -> Int -> IO Int32 readInt64OffAddr :: Addr -> Int -> IO Int64 -- write value into mutable memory writeCharOffAddr :: Addr -> Int -> Char -> IO () writeIntOffAddr :: Addr -> Int -> Int -> IO () -- should we drop this? writeAddrOffAddr :: Addr -> Int -> Addr -> IO () writeFloatOffAddr :: Addr -> Int -> Float -> IO () writeDoubleOffAddr :: Addr -> Int -> Double -> IO () writeWord8OffAddr :: Addr -> Int -> Word8 -> IO () writeWord16OffAddr :: Addr -> Int -> Word16 -> IO () writeWord32OffAddr :: Addr -> Int -> Word32 -> IO () writeWord64OffAddr :: Addr -> Int -> Word64 -> IO () writeInt8OffAddr :: Addr -> Int -> Int8 -> IO () writeInt16OffAddr :: Addr -> Int -> Int16 -> IO () writeInt32OffAddr :: Addr -> Int -> Int32 -> IO () writeInt64OffAddr :: Addr -> Int -> Int64 -> IO ()
Hugs and GHC provide Addr and nullAddr but do not provide any of the index, read or write functions. They can be implemented using GreenCard if required.
This library provides the Concurrent Haskell extensions.
We are grateful to the Glasgow Haskell Project for allowing us to redistribute their implementation of this module.
module Concurrent where data ThreadId -- thread identifiers instance Eq ThreadId forkIO :: IO () -> IO ThreadId killThread :: ThreadId -> IO () data MVar a -- Synchronisation variables newEmptyMVar :: IO (MVar a) newMVar :: a -> IO (MVar a) takeMVar :: MVar a -> IO a putMVar :: MVar a -> a -> IO () swapMVar :: MVar a -> a -> IO a readMVar :: MVar a -> IO a instance Eq (MVar a) data Chan a -- channels newChan :: IO (Chan a) writeChan :: Chan a -> a -> IO () readChan :: Chan a -> IO a dupChan :: Chan a -> IO (Chan a) unReadChan :: Chan a -> a -> IO () readChanContents :: Chan a -> IO [a] writeList2Chan :: Chan a -> [a] -> IO () data CVar a -- one element channels newCVar :: IO (CVar a) putCVar :: CVar a -> a -> IO () getCVar :: CVar a -> IO a data QSem -- General/quantity semaphores newQSem :: Int -> IO QSem waitQSem :: QSem -> IO () signalQSem :: QSem -> IO () data QSemN -- General/quantity semaphores newQSemN :: Int -> IO QSemN waitQSemN :: QSemN -> Int -> IO () signalQSemN :: QSemN -> Int -> IO () type SampleVar a -- Sample variables newEmptySampleVar:: IO (SampleVar a) newSampleVar :: a -> IO (SampleVar a) emptySampleVar :: SampleVar a -> IO () readSampleVar :: SampleVar a -> IO a writeSampleVar :: SampleVar a -> a -> IO ()
Notes:
main = forkIO (write 'a') >> write 'b' where write c = putChar c >> write cwill print either aaaaaaaaaaaaaa... or bbbbbbbbbbbb..., instead of some random interleaving of as and bs. In practice, cooperative multitasking is sufficient for writing simple graphical user interfaces.
This library contains Simon Peyton Jones' implementation of John Hughes's pretty printer combinators.
module Pretty where infixl 6 <> infixl 6 <+> infixl 5 $$, $+$ data Doc -- the Document datatype -- The primitive Doc values empty :: Doc text :: String -> Doc char :: Char -> Doc int :: Int -> Doc integer :: Integer -> Doc float :: Float -> Doc double :: Double -> Doc rational :: Rational -> Doc semi, comma, colon, space, equals :: Doc lparen, rparen, lbrack, rbrack, lbrace, rbrace :: Doc parens, brackets, braces :: Doc -> Doc quotes, doubleQuotes :: Doc -> Doc -- Combining Doc values (<>) :: Doc -> Doc -> Doc -- Beside hcat :: [Doc] -> Doc -- List version of <> (<+>) :: Doc -> Doc -> Doc -- Beside, separated by space hsep :: [Doc] -> Doc -- List version of <+> ($$) :: Doc -> Doc -> Doc -- Above; if there is no -- overlap it "dovetails" the two vcat :: [Doc] -> Doc -- List version of $$ cat :: [Doc] -> Doc -- Either hcat or vcat sep :: [Doc] -> Doc -- Either hsep or vcat fcat :: [Doc] -> Doc -- "Paragraph fill" version of cat fsep :: [Doc] -> Doc -- "Paragraph fill" version of sep nest :: Int -> Doc -> Doc -- Nested hang :: Doc -> Int -> Doc -> Doc punctuate :: Doc -> [Doc] -> [Doc] -- punctuate p [d1, ... dn] = [d1 <> p, d2 <> p, ... dn-1 <> p, dn] -- Displaying Doc values instance Show Doc render :: Doc -> String -- Uses default style renderStyle :: Style -> Doc -> String data Style = Style { lineLength :: Int, -- In chars ribbonsPerLine :: Float, -- Ratio of ribbon length -- to line length mode :: Mode } data Mode = PageMode -- Normal | ZigZagMode -- With zig-zag cuts | LeftMode -- No indentation, infinitely long lines | OneLineMode -- All on one line
If you rely on the implicit `import Prelude' that GHC normally does for you, and if you don't use any weird flags (notably `-fglasgow-exts'), and if you don't import the Glasgow extensions interface, `GlaExts', then GHC should work exactly as the Haskell report says, and the full user namespaces should be available to you.
If you mess about with `import Prelude'... innocent hiding, e.g.,
import Prelude hiding ( fromIntegral )
should work just fine.
If you turn on `-fglasgow-exts', the compiler will recognise and parse unboxed values properly. To get at the primitive operations described herein, import the relevant interfaces.
The `GlaExts' interface provides access to extensions that only GHC implements. These currently are: unboxed types, including the representations of the primitive types (Int, Float, etc.), and the GHC primitive operations (`+#', `==#', etc.).
This module used to provide access to all the Glasgow extensions, but these have since been moved into separate libraries for compatibility with Hugs (version 2.09: in fact, you can still get at this stuff via `GlaExts' for compatibility, but this facility will likely be removed in the future).
-- the representation of some basic types: data Char = C# Char# data Int = I# Int# data Addr = A# Addr# data Word = W# Word# data Float = F# Float# data Double = D# Double# data Integer = J# Int# Int# ByteArray# module GHC -- all primops and primitive types.
The `MutableArray' interface defines a general set of operations over mutable arrays (`MutableArray') and mutable chunks of memory (`MutableByteArray'):
data MutableArray s ix elt -- abstract data MutableByteArray s ix -- abstract -- instance of : CCallable -- Creators: newArray :: Ix ix => (ix,ix) -> elt -> ST s (MutableArray s ix elt) newCharArray :: Ix ix => (ix,ix) -> ST s (MutableByteArray s ix) newAddrArray :: Ix ix => (ix,ix) -> ST s (MutableByteArray s ix) newIntArray :: Ix ix => (ix,ix) -> ST s (MutableByteArray s ix) newFloatArray :: Ix ix => (ix,ix) -> ST s (MutableByteArray s ix) newDoubleArray :: Ix ix => (ix,ix) -> ST s (MutableByteArray s ix) boundsOfArray :: Ix ix => MutableArray s ix elt -> (ix, ix) boundsOfByteArray :: Ix ix => MutableByteArray s ix -> (ix, ix) readArray :: Ix ix => MutableArray s ix elt -> ix -> ST s elt readCharArray :: Ix ix => MutableByteArray s ix -> ix -> ST s Char readIntArray :: Ix ix => MutableByteArray s ix -> ix -> ST s Int readAddrArray :: Ix ix => MutableByteArray s ix -> ix -> ST s Addr readFloatArray :: Ix ix => MutableByteArray s ix -> ix -> ST s Float readDoubleArray :: Ix ix => MutableByteArray s ix -> ix -> ST s Double writeArray :: Ix ix => MutableArray s ix elt -> ix -> elt -> ST s () writeCharArray :: Ix ix => MutableByteArray s ix -> ix -> Char -> ST s () writeIntArray :: Ix ix => MutableByteArray s ix -> ix -> Int -> ST s () writeAddrArray :: Ix ix => MutableByteArray s ix -> ix -> Addr -> ST s () writeFloatArray :: Ix ix => MutableByteArray s ix -> ix -> Float -> ST s () writeDoubleArray :: Ix ix => MutableByteArray s ix -> ix -> Double -> ST s () freezeArray :: Ix ix => MutableArray s ix elt -> ST s (Array ix elt) freezeCharArray :: Ix ix => MutableByteArray s ix -> ST s (ByteArray ix) freezeIntArray :: Ix ix => MutableByteArray s ix -> ST s (ByteArray ix) freezeAddrArray :: Ix ix => MutableByteArray s ix -> ST s (ByteArray ix) freezeFloatArray :: Ix ix => MutableByteArray s ix -> ST s (ByteArray ix) freezeDoubleArray :: Ix ix => MutableByteArray s ix -> ST s (ByteArray ix) unsafeFreezeArray :: Ix ix => MutableArray s ix elt -> ST s (Array ix elt) unsafeFreezeByteArray :: Ix ix => MutableByteArray s ix -> ST s (ByteArray ix) thawArray :: Ix ix => Array ix elt -> ST s (MutableArray s ix elt)
`ByteArray's are chunks of immutable Haskell heap:
data ByteArray ix -- abstract -- instance of: CCallable indexCharArray :: Ix ix => ByteArray ix -> ix -> Char indexIntArray :: Ix ix => ByteArray ix -> ix -> Int indexAddrArray :: Ix ix => ByteArray ix -> ix -> Addr indexFloatArray :: Ix ix => ByteArray ix -> ix -> Float indexDoubleArray :: Ix ix => ByteArray ix -> ix -> Double indexCharOffAddr :: Addr -> Int -> Char indexIntOffAddr :: Addr -> Int -> Int indexAddrOffAddr :: Addr -> Int -> Addr indexFloatOffAddr :: Addr -> Int -> Float indexDoubleOffAddr :: Addr -> Int -> Double
Nothing exciting here, just simple boxing up.
data StablePtr a = StablePtr (StablePtr# a) makeStablePointer :: a -> StablePtr a freeStablePointer :: StablePtr a -> IO ()
This module provides the `ForeignObj' type and wrappers around the primitive operations on foreign objects.
data ForeignObj = ForeignObj ForeignObj# makeForeignObj :: Addr -- object to be boxed up as a ForeignObj -> Addr -- finaliser -> IO ForeignObj writeForeignObj :: ForeignObj -- previously created foreign object -> Addr -- new value -> IO ()
A typical use of `ForeignObj' is in constructing Haskell bindings to external libraries. A good example is that of writing a binding to an image-processing library (which was actually the main motivation for implementing `ForeignObj''s precursor, `MallocPtr#'). The images manipulated are not stored in the Haskell heap, either because the library insist on allocating them internally or we (sensibly) decide to spare the GC from having to heave heavy images around.
data Image = Image ForeignObj
The `ForeignObj' type is then used to refer to the externally allocated image, and to acheive some type safety, the Haskell binding defines the `Image' data type. So, a value of type `ForeignObj' is used to "box" up an external reference into a Haskell heap object that we can then indirectly reference:
createImage :: (Int,Int) -> IO Image
So far, this looks just like an `Addr' type, but `ForeignObj' offers a bit more, namely that we can specify a finalisation routine to invoke when the `ForeignObj' is discarded by the GC. The garbage collector invokes the finalisation routine associated with the `ForeignObj', saying " Thanks, I'm through with this now.." For the image-processing library, the finalisation routine could for the images free up memory allocated for them. The finalisation routine has currently to be written in C (the finalisation routine can in turn call on `FreeStablePtr' to deallocate a stable pointer).
Associating a finalisation routine with an external object is done by calling `makeForeignObj'. Note: the foreign object value and its finaliser are contained in the `ForeignObj', so there's no danger of an aggressive optimiser somehow separating the two (with the result that the foreign reference would not be freed).
(Implementation: a linked list of all `ForeignObj#'s is maintained to allow the garbage collector to detect when a `ForeignObj#' becomes garbage.)
Like `Array', `ForeignObj#'s are represented by heap objects.
Upon controlled termination of the Haskell program, all `ForeignObjs' are freed, invoking their respective finalisers before terminating.
The `CCall' module defines the classes `CCallable' and `CReturnable', along with instances for the primitive types (`Int', `Int#', `Float', `Float#' etc.) GHC knows to import this module if you use `_ccall_', but if you need to define your own instances of these classes, you will need to import `CCall' explicitly.
More information on how to use `_ccall_' can be found in Section 8.5 Calling C directly from Haskell.
This section gives an overview of the interfaces provided by the different syslibs that comes bundled with GHC.
At the moment, there four different collections of system libraries:
If you provide a `-syslib <name>' option on the command line, then the interfaces for that library will come into scope (and may be `import'ed), and the code will be added in at link time.
We have started to put together a "GHC system library."
At the moment, the library is made of generally-useful bits of the compiler itself.
To use this library, just give a `-syslib ghc' option to GHC, both for compiling and linking.
A bag is an unordered collection of elements which may contain duplicates. To use, `import Bag'.
data Bag elt -- abstract emptyBag :: Bag elt unitBag :: elt -> Bag elt consBag :: elt -> Bag elt -> Bag elt snocBag :: Bag elt -> elt -> Bag elt unionBags :: Bag elt -> Bag elt -> Bag elt unionManyBags :: [Bag elt] -> Bag elt isEmptyBag :: Bag elt -> Bool elemBag :: Eq elt => elt -> Bag elt -> Bool filterBag :: (elt -> Bool) -> Bag elt -> Bag elt partitionBag :: (elt -> Bool) -> Bag elt-> (Bag elt, Bag elt) -- returns the elements that do/don't satisfy the predicate concatBag :: Bag (Bag a) -> Bag a foldBag :: (r -> r -> r) -> (a -> r) -> r -> Bag a -> r mapBag :: (a -> b) -> Bag a -> Bag b listToBag :: [elt] -> Bag elt bagToList :: Bag elt -> [elt]
What functional programmers call a finite map, everyone else calls a lookup table.
Out code is derived from that in this paper:
S Adams "Efficient sets: a balancing act" Journal of functional programming 3(4) Oct 1993, pages 553-562
Guess what? The implementation uses balanced trees.
data FiniteMap key elt -- abstract -- BUILDING emptyFM :: FiniteMap key elt unitFM :: key -> elt -> FiniteMap key elt listToFM :: Ord key => [(key,elt)] -> FiniteMap key elt -- In the case of duplicates, the last is taken -- ADDING AND DELETING -- Throws away any previous binding -- In the list case, the items are added starting with the -- first one in the list addToFM :: Ord key => FiniteMap key elt -> key -> elt -> FiniteMap key elt addListToFM :: Ord key => FiniteMap key elt -> [(key,elt)] -> FiniteMap key elt -- Combines with previous binding -- In the combining function, the first argument is -- the "old" element, while the second is the "new" one. addToFM_C :: Ord key => (elt -> elt -> elt) -> FiniteMap key elt -> key -> elt -> FiniteMap key elt addListToFM_C :: Ord key => (elt -> elt -> elt) -> FiniteMap key elt -> [(key,elt)] -> FiniteMap key elt -- Deletion doesn't complain if you try to delete something -- which isn't there delFromFM :: Ord key => FiniteMap key elt -> key -> FiniteMap key elt delListFromFM :: Ord key => FiniteMap key elt -> [key] -> FiniteMap key elt -- COMBINING -- Bindings in right argument shadow those in the left plusFM :: Ord key => FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt -- Combines bindings for the same thing with the given function plusFM_C :: Ord key => (elt -> elt -> elt) -> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt minusFM :: Ord key => FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt -- (minusFM a1 a2) deletes from a1 any bindings which are bound in a2 intersectFM :: Ord key => FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt intersectFM_C :: Ord key => (elt -> elt -> elt) -> FiniteMap key elt -> FiniteMap key elt -> FiniteMap key elt -- MAPPING, FOLDING, FILTERING foldFM :: (key -> elt -> a -> a) -> a -> FiniteMap key elt -> a mapFM :: (key -> elt1 -> elt2) -> FiniteMap key elt1 -> FiniteMap key elt2 filterFM :: Ord key => (key -> elt -> Bool) -> FiniteMap key elt -> FiniteMap key elt -- INTERROGATING sizeFM :: FiniteMap key elt -> Int isEmptyFM :: FiniteMap key elt -> Bool elemFM :: Ord key => key -> FiniteMap key elt -> Bool lookupFM :: Ord key => FiniteMap key elt -> key -> Maybe elt lookupWithDefaultFM :: Ord key => FiniteMap key elt -> elt -> key -> elt -- lookupWithDefaultFM supplies a "default" elt -- to return for an unmapped key -- LISTIFYING fmToList :: FiniteMap key elt -> [(key,elt)] keysFM :: FiniteMap key elt -> [key] eltsFM :: FiniteMap key elt -> [elt]
Just a few set-sounding operations on lists. If you want sets, use the `Set' module.
unionLists :: Eq a => [a] -> [a] -> [a] intersectLists :: Eq a => [a] -> [a] -> [a] minusList :: Eq a => [a] -> [a] -> [a] disjointLists :: Eq a => [a] -> [a] -> Bool intersectingLists :: Eq a => [a] -> [a] -> Bool
The `Maybe' type is in the Haskell 1.4 prelude. Moreover, the required `Maybe' library provides many useful functions on `Maybe's. This (pre-1.3) module provides some more:
An `Either'-like type called `MaybeErr':
data MaybeErr val err = Succeeded val | Failed err
Some operations to do with `Maybe' (some commentary follows):
maybeToBool :: Maybe a -> Bool -- Nothing => False; Just => True allMaybes :: [Maybe a] -> Maybe [a] firstJust :: [Maybe a] -> Maybe a findJust :: (a -> Maybe b) -> [a] -> Maybe b assocMaybe :: Eq a => [(a,b)] -> a -> Maybe b mkLookupFun :: (key -> key -> Bool) -- Equality predicate -> [(key,val)] -- The assoc list -> (key -> Maybe val) -- A lookup fun to use mkLookupFunDef :: (key -> key -> Bool) -- Equality predicate -> [(key,val)] -- The assoc list -> val -- Value to return on failure -> key -- The key -> val -- The corresponding value -- a monad thing thenMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b returnMaybe :: a -> Maybe a failMaybe :: Maybe a mapMaybe :: (a -> Maybe b) -> [a] -> Maybe [b]
NB: `catMaybes' which used to be here, is now available via the standard `Maybe' interface (`Maybe' is an instance of `MonadPlus').
`allMaybes' collects a list of `Justs' into a single `Just', returning `Nothing' if there are any `Nothings'.
`firstJust' takes a list of `Maybes' and returns the first `Just' if there is one, or `Nothing' otherwise.
`assocMaybe' looks up in an association list, returning `Nothing' if it fails.
Now, some operations to do with `MaybeErr' (comments follow):
-- a monad thing (surprise, surprise) thenMaB :: MaybeErr a err -> (a -> MaybeErr b err) -> MaybeErr b err returnMaB :: val -> MaybeErr val err failMaB :: err -> MaybeErr val err listMaybeErrs :: [MaybeErr val err] -> MaybeErr [val] [err] foldlMaybeErrs :: (acc -> input -> MaybeErr acc err) -> acc -> [input] -> MaybeErr acc [err]
`listMaybeErrs' takes a list of `MaybeErrs' and, if they all succeed, returns a `Succeeded' of a list of their values. If any fail, it returns a `Failed' of the list of all the errors in the list.
`foldlMaybeErrs' works along a list, carrying an accumulator; it applies the given function to the accumulator and the next list item, accumulating any errors that occur.
You need to `import PackedString' and heave in your `-syslib ghc' to use `PackedString's.
The basic type and functions available are:
data PackedString -- abstract packString :: [Char] -> PackedString packStringST :: [Char] -> ST s PackedString packCBytesST :: Int -> Addr -> ST s PackedString packBytesForCST :: [Char] -> ST s (ByteArray Int) byteArrayToPS :: ByteArray Int -> PackedString unsafeByteArrayToPS :: ByteArray a -> Int -> PackedString psToByteArray :: PackedString -> ByteArray Int psToByteArrayST :: PackedString -> ST s (ByteArray Int) unpackPS :: PackedString -> [Char]
We also provide a wad of list-manipulation-like functions:
nilPS :: PackedString consPS :: Char -> PackedString -> PackedString headPS :: PackedString -> Char tailPS :: PackedString -> PackedString nullPS :: PackedString -> Bool appendPS :: PackedString -> PackedString -> PackedString lengthPS :: PackedString -> Int indexPS :: PackedString -> Int -> Char -- 0-origin indexing into the string mapPS :: (Char -> Char) -> PackedString -> PackedString filterPS :: (Char -> Bool) -> PackedString -> PackedString foldlPS :: (a -> Char -> a) -> a -> PackedString -> a foldrPS :: (Char -> a -> a) -> a -> PackedString -> a takePS :: Int -> PackedString -> PackedString dropPS :: Int -> PackedString -> PackedString splitAtPS :: Int -> PackedString -> (PackedString, PackedString) takeWhilePS :: (Char -> Bool) -> PackedString -> PackedString dropWhilePS :: (Char -> Bool) -> PackedString -> PackedString spanPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString) breakPS :: (Char -> Bool) -> PackedString -> (PackedString, PackedString) linesPS :: PackedString -> [PackedString] wordsPS :: PackedString -> [PackedString] reversePS :: PackedString -> PackedString concatPS :: [PackedString] -> PackedString elemPS :: Char -> PackedString -> Bool -- Perl-style split&join splitPS :: Char -> PackedString -> [PackedString] splitWithPS :: (Char -> Bool) -> PackedString -> [PackedString] joinPS :: PackedString -> [PackedString] -> PackedString substrPS :: PackedString -> Int -> Int -> PackedString -- pluck out a piece of a PackedString -- start and end chars you want; both 0-origin-specified
This is the pretty-printer that is currently used in GHC:
type Pretty ppShow :: Int{-width-} -> Pretty -> [Char] pp'SP :: Pretty -- "comma space" ppComma :: Pretty -- , ppEquals :: Pretty -- = ppLbrack :: Pretty -- [ ppLparen :: Pretty -- ( ppNil :: Pretty -- nothing ppRparen :: Pretty -- ) ppRbrack :: Pretty -- ] ppSP :: Pretty -- space ppSemi :: Pretty -- ; ppChar :: Char -> Pretty ppDouble :: Double -> Pretty ppFloat :: Float -> Pretty ppInt :: Int -> Pretty ppInteger :: Integer -> Pretty ppRational :: Rational -> Pretty ppStr :: [Char] -> Pretty ppAbove :: Pretty -> Pretty -> Pretty ppAboves :: [Pretty] -> Pretty ppBeside :: Pretty -> Pretty -> Pretty ppBesides :: [Pretty] -> Pretty ppCat :: [Pretty] -> Pretty ppHang :: Pretty -> Int -> Pretty -> Pretty ppInterleave :: Pretty -> [Pretty] -> Pretty -- spacing between ppIntersperse :: Pretty -> [Pretty] -> Pretty -- no spacing between ppNest :: Int -> Pretty -> Pretty ppSep :: [Pretty] -> Pretty
Our implementation of sets (key property: no duplicates) is just a variant of the `FiniteMap' module.
data Set -- abstract -- instance of: Eq emptySet :: Set a mkSet :: Ord a => [a] -> Set a setToList :: Set a -> [a] unitSet :: a -> Set a singletonSet :: a -> Set a -- deprecated, use unitSet. union :: Ord a => Set a -> Set a -> Set a unionManySets :: Ord a => [Set a] -> Set a minusSet :: Ord a => Set a -> Set a -> Set a mapSet :: Ord a => (b -> a) -> Set b -> Set a intersect :: Ord a => Set a -> Set a -> Set a elementOf :: Ord a => a -> Set a -> Bool isEmptySet :: Set a -> Bool cardinality :: Set a -> Int
Bit sets are a fast implementation of sets of integers ranging from 0 to one less than the number of bits in a machine word (typically 31). If any element exceeds the maximum value for a particular machine architecture, the results of these operations are undefined. You have been warned.
data BitSet -- abstract -- instance of: emptyBS :: BitSet mkBS :: [Int] -> BitSet unitBS :: Int -> BitSet unionBS :: BitSet -> BitSet -> BitSet minusBS :: BitSet -> BitSet -> BitSet isEmptyBS :: BitSet -> Bool intersectBS :: BitSet -> BitSet -> BitSet elementBS :: Int -> BitSet -> Bool listBS :: BitSet -> [Int]
Stuff that has been generally useful to use in writing the compiler. Don't be too surprised if this stuff moves/gets-renamed/etc.
-- general list processing forall :: (a -> Bool) -> [a] -> Bool exists :: (a -> Bool) -> [a] -> Bool nOfThem :: Int -> a -> [a] lengthExceeds :: [a] -> Int -> Bool isSingleton :: [a] -> Bool --paranoid zip'ing (equal length lists) zipEqual :: [a] -> [b] -> [(a,b)] zipWithEqual :: String -> (a->b->c) -> [a]->[b]->[c] zipWith3Equal :: String -> (a->b->c->d) -> [a]->[b]->[c]->[d] zipWith4Equal :: String -> (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e] -- lazy in second argument zipLazy :: [a] -> [b] -> [(a,b)] mapAndUnzip :: (a -> (b, c)) -> [a] -> ([b], [c]) mapAndUnzip3 :: (a -> (b, c, d)) -> [a] -> ([b], [c], [d]) -- prefix and suffix matching on lists of characters. startsWith :: {-prefix-}String -> String -> Maybe String endsWith :: {-suffix-}String -> String -> Maybe String -- association lists assoc :: Eq a => String -> [(a, b)] -> a -> b -- duplicate handling hasNoDups :: Eq a => [a] -> Bool equivClasses :: (a -> a -> Ordering) -> [a] -> [[a]] runs :: (a -> a -> Bool) -> [a] -> [[a]] removeDups :: (a -> a -> Ordering) -> [a] -> ([a], [[a]]) -- sorting (don't complain of no choice...) quicksort :: (a -> a -> Bool) -> [a] -> [a] sortLt :: (a -> a -> Bool) -> [a] -> [a] stableSortLt :: (a -> a -> Bool) -> [a] -> [a] mergesort :: (a -> a -> _CMP_TAG) -> [a] -> [a] mergeSort :: Ord a => [a] -> [a] naturalMergeSort :: Ord a => [a] -> [a] mergeSortLe :: Ord a => [a] -> [a] naturalMergeSortLe :: Ord a => [a] -> [a] -- transitive closures transitiveClosure :: (a -> [a]) -- Successor function -> (a -> a -> Bool) -- Equality predicate -> [a] -> [a] -- The transitive closure -- accumulating (Left, Right, Bi-directional) mapAccumL :: (acc -> x -> (acc, y)) -- Function of elt of input list and -- accumulator, returning new accumulator and -- elt of result list -> acc -- Initial accumulator -> [x] -- Input list -> (acc, [y]) -- Final accumulator and result list mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) mapAccumB :: (accl -> accr -> x -> (accl, accr,y)) -> accl -> accr -> [x] -> (accl, accr, [y]) --list comparison with explicit element comparer. cmpList :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering -- pairs applyToPair :: ((a -> c), (b -> d)) -> (a, b) -> (c, d) applyToFst :: (a -> c) -> (a, b) -> (c, b) applyToSnd :: (b -> d) -> (a, b) -> (a, d) foldPair :: (a->a->a, b->b->b) -> (a, b) -> [(a, b)] -> (a, b) unzipWith :: (a -> b -> c) -> [(a, b)] -> [c]
The GHC system library (`-syslib ghc') also provides interfaces to several useful C libraries, mostly from the GNU project.
(Darren Moffat supplied the `Readline' interface.)
The `Readline' module is a straightforward interface to the GNU Readline library. As such, you will need to look at the GNU documentation (and have a `libreadline.a' file around somewhere...)
You'll need to link any Readlining program with `-lreadline -ltermcap', besides the usual `-syslib ghc' (and `-fhaskell-1.3').
The main function you'll use is:
readline :: String{-the prompt-} -> IO String
If you want to mess around with Full Readline G(l)ory, we also provide:
rlInitialize, addHistory, rlBindKey, rlAddDefun, RlCallbackFunction(..), rlGetLineBuffer, rlSetLineBuffer, rlGetPoint, rlSetPoint, rlGetEnd, rlSetEnd, rlGetMark, rlSetMark, rlSetDone, rlPendingInput, rlPrompt, rlTerminalName, rlSetReadlineName, rlGetReadlineName
(All those names are just Haskellised versions of what you will see in the GNU readline documentation.)
(Sigbjorn Finne supplied the regular-expressions interface.)
The `Regex' library provides quite direct interface to the GNU regular-expression library, for doing manipulation on `PackedString's. You probably need to see the GNU documentation if you are operating at this level.
The datatypes and functions that `Regex' provides are:
data PatBuffer # just a bunch of bytes (mutable) data REmatch = REmatch (Array Int GroupBounds) -- for $1, ... $n GroupBounds -- for $` (everything before match) GroupBounds -- for $& (entire matched string) GroupBounds -- for $' (everything after) GroupBounds -- for $+ (matched by last bracket) -- GroupBounds hold the interval where a group -- matched inside a string, e.g. -- -- matching "reg(exp)" "a regexp" returns the pair (5,7) for the -- (exp) group. (PackedString indices start from 0) type GroupBounds = (Int, Int) re_compile_pattern :: PackedString -- pattern to compile -> Bool -- True <=> assume single-line mode -> Bool -- True <=> case-insensitive -> PrimIO PatBuffer re_match :: PatBuffer -- compiled regexp -> PackedString -- string to match -> Int -- start position -> Bool -- True <=> record results in registers -> PrimIO (Maybe REmatch) -- Matching on 2 strings is useful when you're dealing with multiple -- buffers, which is something that could prove useful for -- PackedStrings, as we don't want to stuff the contents of a file -- into one massive heap chunk, but load (smaller chunks) on demand. re_match2 :: PatBuffer -- 2-string version -> PackedString -> PackedString -> Int -> Int -> Bool -> PrimIO (Maybe REmatch) re_search :: PatBuffer -- compiled regexp -> PackedString -- string to search -> Int -- start index -> Int -- stop index -> Bool -- True <=> record results in registers -> PrimIO (Maybe REmatch) re_search2 :: PatBuffer -- Double buffer search -> PackedString -> PackedString -> Int -- start index -> Int -- range (?) -> Int -- stop index -> Bool -- True <=> results in registers -> PrimIO (Maybe REmatch)
The `MatchPS' module provides Perl-like "higher-level" facilities to operate on `PackedStrings'. The regular expressions in question are in Perl syntax. The "flags" on various functions can include: `i' for case-insensitive, `s' for single-line mode, and `g' for global. (It's probably worth your time to peruse the source code...)
matchPS :: PackedString -- regexp -> PackedString -- string to match -> [Char] -- flags -> Maybe REmatch -- info about what matched and where searchPS :: PackedString -- regexp -> PackedString -- string to match -> [Char] -- flags -> Maybe REmatch -- Perl-like match-and-substitute: substPS :: PackedString -- regexp -> PackedString -- replacement -> [Char] -- flags -> PackedString -- string -> PackedString -- same as substPS, but no prefix and suffix: replacePS :: PackedString -- regexp -> PackedString -- replacement -> [Char] -- flags -> PackedString -- string -> PackedString match2PS :: PackedString -- regexp -> PackedString -- string1 to match -> PackedString -- string2 to match -> [Char] -- flags -> Maybe REmatch search2PS :: PackedString -- regexp -> PackedString -- string to match -> PackedString -- string to match -> [Char] -- flags -> Maybe REmatch -- functions to pull the matched pieces out of an REmatch: getMatchesNo :: REmatch -> Int getMatchedGroup :: REmatch -> Int -> PackedString -> PackedString getWholeMatch :: REmatch -> PackedString -> PackedString getLastMatch :: REmatch -> PackedString -> PackedString getAfterMatch :: REmatch -> PackedString -> PackedString -- (reverse) brute-force string matching; -- Perl equivalent is index/rindex: findPS, rfindPS :: PackedString -> PackedString -> Maybe Int -- Equivalent to Perl "chop" (off the last character, if any): chopPS :: PackedString -> PackedString -- matchPrefixPS: tries to match as much as possible of strA starting -- from the beginning of strB (handy when matching fancy literals in -- parsers): matchPrefixPS :: PackedString -> PackedString -> Int
(Darren Moffat supplied the network-interface toolkit.)
Your best bet for documentation is to look at the code -- really! -- normally in `hslibs/ghc/src/{BSD,Socket,SocketPrim}.lhs'.
The `BSD' module provides functions to get at system-database info;
pretty straightforward if you're into this sort of thing:
getHostName :: IO String getServiceByName :: ServiceName -> IO ServiceEntry getServicePortNumber:: ServiceName -> IO PortNumber getServiceEntry :: IO ServiceEntry setServiceEntry :: Bool -> IO () endServiceEntry :: IO () getProtocolByName :: ProtocolName -> IO ProtocolEntry getProtocolByNumber :: ProtocolNumber -> IO ProtcolEntry getProtocolNumber :: ProtocolName -> ProtocolNumber getProtocolEntry :: IO ProtocolEntry setProtocolEntry :: Bool -> IO () endProtocolEntry :: IO () getHostByName :: HostName -> IO HostEntry getHostByAddr :: Family -> HostAddress -> IO HostEntry getHostEntry :: IO HostEntry setHostEntry :: Bool -> IO () endHostEntry :: IO ()
The `SocketPrim' interface provides quite direct access to the socket facilities in a BSD Unix system, including all the complications. We hope you don't need to use it! See the source if needed...
The `Socket' interface is a "higher-level" interface to sockets, and it is what we recommend. Please tell us if the facilities it offers are inadequate to your task!
The interface is relatively modest:
connectTo :: Hostname -> PortID -> IO Handle listenOn :: PortID -> IO Socket accept :: Socket -> IO (Handle, HostName) sendTo :: Hostname -> PortID -> String -> IO () recvFrom :: Hostname -> PortID -> IO String socketPort :: Socket -> IO PortID data PortID -- PortID is a non-abstract type = Service String -- Service Name eg "ftp" | PortNumber Int -- User defined Port Number | UnixSocket String -- Unix family socket in file system type Hostname = String
Various examples of networking Haskell code are provided in
The `Posix' interface gives you access to the set of OS services standardised by POSIX 1003.1b (or the IEEE Portable Operating System Interface for Computing Environments - IEEE Std. 1003.1). The interface is accessed by `import Posix' and adding `-syslib posix' on your command-line.
data ByteCount -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `ByteCount' is a primitive of type `unsigned'. At a minimum, an conforming implementation must support values in the range `[0, UINT_MAX]'.
data ClockTick -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `ClockTick' is a primitive of type `clock_t', which is used to measure intervals of time in fractions of a second. The resolution is determined by `getSysVar ClockTick'.
data DeviceID -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `DeviceID' is a primitive of type `dev_t'. It must be an arithmetic type.
data EpochTime -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `EpochTime' is a primitive of type `time_t', which is used to measure seconds since the Epoch. At a minimum, the implementation must support values in the range `[0, INT_MAX]'.
data FileID -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `FileID' is a primitive of type `ino_t'. It must be an arithmetic type.
data FileMode -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `FileMode' is a primitive of type `mode_t'. It must be an arithmetic type.
data FileOffset -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `FileOffset' is a primitive of type `off_t'. It must be an arithmetic type.
data GroupID -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `GroupID' is a primitive of type `gid_t'. It must be an arithmetic type.
data Limit -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `Limit' is a primitive of type `long'. At a minimum, the implementation must support values in the range `[LONG_MIN, LONG_MAX]'.
data LinkCount -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `LinkCount' is a primitive of type `nlink_t'. It must be an arithmetic type.
data ProcessID -- instances of : Eq Ord Num Real Integral Ix Enum Show type ProcessGroupID = ProcessID
A `ProcessID' is a primitive of type `pid_t'. It must be a signed arithmetic type.
data UserID -- instances of : Eq Ord Num Real Integral Ix Enum Show
A `UserID' is a primitive of type `uid_t'. It must be an arithmetic type.
data DirStream
A `DirStream' is a primitive of type `DIR *'.
data FileStatus
A `FileStatus' is a primitive of type `struct stat'.
data GroupEntry
A `GroupEntry' is a primitive of type `struct group'.
data ProcessTimes
`ProcessTimes' is a primitive structure containing a `clock_t' and a `struct tms'.
data SignalSet
An `SignalSet' is a primitive of type `sigset_t'.
data SystemID
A `SystemID' is a primitive of type `struct utsname'.
data TerminalAttributes
`TerminalAttributes' is a primitive of type `struct termios'.
data UserEntry
A `UserEntry' is a primitive of type `struct passwd'.
data BaudRate = B0 | B50 | B75 | B110 | B134 | B150 | B200 | B300 | B600 | B1200 | B1800 | B2400 | B4800 | B9600 | B19200 | B38400 deriving (Eq, Show) data Fd intToFd :: Int -> Fd -- use with care. data FdOption = AppendOnWrite | CloseOnExec | NonBlockingRead data ControlCharacter = EndOfFile | EndOfLine | Erase | Interrupt | Kill | Quit | Suspend | Start | Stop type ErrorCode = Int type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset) -- whence start length data FlowAction = SuspendOutput | RestartOutput | TransmitStop | TransmitStart data Handler = Default | Ignore | Catch (IO ()) data LockRequest = ReadLock | WriteLock | Unlock deriving (Eq, Show) data OpenMode = ReadOnly | WriteOnly | ReadWrite data PathVar = LinkLimit | InputLineLimit | InputQueueLimit | FileNameLimit | PathNameLimit | PipeBufferLimit | SetOwnerAndGroupIsRestricted | FileNamesAreNotTruncated data QueueSelector = InputQueue | OutputQueue | BothQueues type Signal = Int data SysVar = ArgumentLimit | ChildLimit | ClockTick | GroupLimit | OpenFileLimit | PosixVersion | HasSavedIDs | HasJobControl data TerminalMode = InterruptOnBreak -- BRKINT | MapCRtoLF -- ICRNL | IgnoreBreak -- IGNBRK | IgnoreCR -- IGNCR | IgnoreParityErrors -- IGNPAR | MapLFtoCR -- INLCR | CheckParity -- INPCK | StripHighBit -- ISTRIP | StartStopInput -- IXOFF | StartStopOutput -- IXON | MarkParityErrors -- PARMRK | ProcessOutput -- OPOST | LocalMode -- CLOCAL | ReadEnable -- CREAD | TwoStopBits -- CSTOPB | HangupOnClose -- HUPCL | EnableParity -- PARENB | OddParity -- PARODD | EnableEcho -- ECHO | EchoErase -- ECHOE | EchoKill -- ECHOK | EchoLF -- ECHONL | ProcessInput -- ICANON | ExtendedFunctions -- IEXTEN | KeyboardInterrupts -- ISIG | NoFlushOnInterrupt -- NOFLSH | BackgroundWriteInterrupt -- TOSTOP data TerminalState = Immediately | WhenDrained | WhenFlushed data ProcessStatus = Exited ExitCode | Terminated Signal | Stopped Signal deriving (Eq, Show)
forkProcess :: IO (Maybe ProcessID)
`forkProcess' calls `fork', returning `Just pid' to the parent, where `pid' is the ProcessID of the child, and returning `Nothing' to the child.
executeFile :: FilePath -- Command -> Bool -- Search PATH? -> [String] -- Arguments -> Maybe [(String, String)] -- Environment -> IO ()
`executeFile cmd args env' calls one of the `execv*' family, depending on whether or not the current PATH is to be searched for the command, and whether or not an environment is provided to supersede the process's current environment. The basename (leading directory names suppressed) of the command is passed to `execv*' as `arg[0]'; the argument list passed to `executeFile' therefore begins with `arg[1]'.
Search PATH? Supersede environ? Call ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ~~~~~~~ False False execv False True execve True False execvp True True execvpe*
Note that `execvpe' is not provided by the POSIX standard, and must be written by hand. Care must be taken to ensure that the search path is extracted from the original environment, and not from the environment to be passed on to the new image.
A successful `executeFile' overlays the current process image with a new one, so it only returns on failure.
runProcess :: FilePath -- Command -> [String] -- Arguments -> Maybe [(String, String)] -- Environment (Nothing -> Inherited) -> Maybe FilePath -- Working directory (Nothing -> inherited) -> Maybe Handle -- stdin (Nothing -> inherited) -> Maybe Handle -- stdout (Nothing -> inherited) -> Maybe Handle -- stderr (Nothing -> inherited) -> IO ()
`runProcess' is our candidate for the high-level OS-independent primitive.
`runProcess cmd args env wd inhdl outhdl errhdl' runs `cmd' (searching the current `PATH') with arguments `args'. If `env' is `Just pairs', the command is executed with the environment specified by `pairs' of variables and values; otherwise, the command is executed with the current environment. If `wd' is `Just dir', the command is executed with working directory `dir'; otherwise, the command is executed in the current working directory. If `{in,out,err}hdl' is `Just handle', the command is executed with the `Fd' for `std{in,out,err}' attached to the specified `handle'; otherwise, the `Fd' for `std{in,out,err}' is left unchanged.
getProcessStatus :: Bool -- Block? -> Bool -- Stopped processes? -> ProcessID -> IO (Maybe ProcessStatus)
`getProcessStatus blk stopped pid' calls `waitpid', returning `Just tc', the `ProcessStatus' for process `pid' if it is available, `Nothing' otherwise. If `blk' is `False', then `WNOHANG' is set in the options for `waitpid', otherwise not. If `stopped' is `True', then `WUNTRACED' is set in the options for `waitpid', otherwise not.
getGroupProcessStatus :: Bool -- Block? -> Bool -- Stopped processes? -> ProcessGroupID -> IO (Maybe (ProcessID, ProcessStatus))
`getGroupProcessStatus blk stopped pgid' calls `waitpid', returning `Just (pid, tc)', the `ProcessID' and `ProcessStatus' for any process in group `pgid' if one is available, `Nothing' otherwise. If `blk' is `False', then `WNOHANG' is set in the options for `waitpid', otherwise not. If `stopped' is `True', then `WUNTRACED' is set in the options for `waitpid', otherwise not.
getAnyProcessStatus :: Bool -- Block? -> Bool -- Stopped processes? -> IO (Maybe (ProcessID, ProcessStatus))
`getAnyProcessStatus blk stopped' calls `waitpid', returning `Just (pid, tc)', the `ProcessID' and `ProcessStatus' for any child process if one is available, `Nothing' otherwise. If `blk' is `False', then `WNOHANG' is set in the options for `waitpid', otherwise not. If `stopped' is `True', then `WUNTRACED' is set in the options for `waitpid', otherwise not.
exitImmediately :: ExitCode -> IO ()
`exitImmediately status' calls `_exit' to terminate the process with the indicated exit `status'. The operation never returns.
getEnvironment :: IO [(String, String)]
`getEnvironment' parses the environment variable mapping provided by `environ', returning `(variable, value)' pairs. The operation never fails.
setEnvironment :: [(String, String)] -> IO ()
`setEnvironment' replaces the process environment with the provided mapping of `(variable, value)' pairs.
getEnvVar :: String -> IO String
`getEnvVar var' returns the value associated with variable `var' in the current environment (identical functionality provided through standard Haskell library function `System.getEnv').
The operation may fail with:
setEnvVar :: String -> String -> IO ()
`setEnvVar var val' sets the value associated with variable `var' in the current environment to be `val'. Any previous mapping is superseded.
removeEnvVar :: String -> IO ()
`removeEnvVar var' removes any value associated with variable `var' in the current environment. Deleting a variable for which there is no mapping does not generate an error.
nullSignal :: Signal nullSignal = 0 backgroundRead, sigTTIN :: Signal backgroundWrite, sigTTOU :: Signal continueProcess, sigCONT :: Signal floatingPointException, sigFPE :: Signal illegalInstruction, sigILL :: Signal internalAbort, sigABRT :: Signal keyboardSignal, sigINT :: Signal keyboardStop, sigTSTP :: Signal keyboardTermination, sigQUIT :: Signal killProcess, sigKILL :: Signal lostConnection, sigHUP :: Signal openEndedPipe, sigPIPE :: Signal processStatusChanged, sigCHLD :: Signal realTimeAlarm, sigALRM :: Signal segmentationViolation, sigSEGV :: Signal softwareStop, sigSTOP :: Signal softwareTermination, sigTERM :: Signal userDefinedSignal1, sigUSR1 :: Signal userDefinedSignal2, sigUSR2 :: Signal signalProcess :: Signal -> ProcessID -> IO ()
`signalProcess int pid' calls `kill' to signal process `pid' with interrupt signal `int'.
raiseSignal :: Signal -> IO ()
`raiseSignal int' calls `kill' to signal the current process with interrupt signal `int'.
signalProcessGroup :: Signal -> ProcessGroupID -> IO ()
`signalProcessGroup int pgid' calls `kill' to signal all processes in group `pgid' with interrupt signal `int'.
setStoppedChildFlag :: Bool -> IO Bool
`setStoppedChildFlag bool' sets a flag which controls whether or not the `NOCLDSTOP' option will be used the next time a signal handler is installed for `SIGCHLD'. If `bool' is `True' (the default), `NOCLDSTOP' will not be used; otherwise it will be. The operation never fails.
queryStoppedChildFlag :: IO Bool
`queryStoppedChildFlag' queries the flag which controls whether or not the `NOCLDSTOP' option will be used the next time a signal handler is installed for `SIGCHLD'. If `NOCLDSTOP' will be used, it returns `False'; otherwise (the default) it returns `True'. The operation never fails.
emptySignalSet :: SignalSet fullSignalSet :: SignalSet addSignal :: Signal -> SignalSet -> SignalSet deleteSignal :: Signal -> SignalSet -> SignalSet inSignalSet :: Signal -> SignalSet -> Bool installHandler :: Signal -> Handler -> Maybe SignalSet -- other signals to block -> IO Handler -- old handler
`installHandler int handler iset' calls `sigaction' to install an interrupt handler for signal `int'. If `handler' is `Default', `SIG_DFL' is installed; if `handler' is `Ignore', `SIG_IGN' is installed; if `handler' is `Catch action', a handler is installed which will invoke `action' as a replacement for `main'. If `iset' is `Just s', then the `sa_mask' of the `sigaction' structure is set to `s'; otherwise it is cleared. The previously installed signal handler for `int' is returned.
getSignalMask :: IO SignalSet
`getSignalMask' calls `sigprocmask' to determine the set of interrupts which are currently being blocked.
setSignalMask :: SignalSet -> IO SignalSet
`setSignalMask mask' calls `sigprocmask' with `SIG_SETMASK' to block all interrupts in `mask'. The previous set of blocked interrupts is returned.
blockSignals :: SignalSet -> IO SignalSet
`setSignalMask mask' calls `sigprocmask' with `SIG_BLOCK' to add all interrupts in `mask' to the set of blocked interrupts. The previous set of blocked interrupts is returned.
unBlockSignals :: SignalSet -> IO SignalSet
`setSignalMask mask' calls `sigprocmask' with `SIG_UNBLOCK' to remove all interrupts in `mask' from the set of blocked interrupts. The previous set of blocked interrupts is returned.
getPendingSignals :: IO SignalSet
`getPendingSignals' calls `sigpending' to obtain the set of interrupts which have been received but are currently blocked.
awaitSignal :: Maybe SignalSet -> IO ()
`awaitSignal iset' suspends execution until an interrupt is received. If `iset' is `Just s', `awaitSignal' calls `sigsuspend', installing `s' as the new signal mask before suspending execution; otherwise, it calls `pause'. If successful, `awaitSignal' does not return.
scheduleAlarm :: Int -> IO Int
`scheduleAlarm i' calls `alarm' to schedule a real time alarm at least `i' seconds in the future.
sleep :: Int -> IO ()
`sleep i' calls `sleep' to suspend execution of the program until at least `i' seconds have elapsed or a signal is received.
getProcessID :: IO ProcessID
`getProcessID' calls `getpid' to obtain the `ProcessID' for the current process.
getParentProcessID :: IO ProcessID
`getProcessID' calls `getppid' to obtain the `ProcessID' for the parent of the current process.
getRealUserID :: IO UserID
`getRealUserID' calls `getuid' to obtain the real `UserID' associated with the current process.
getEffectiveUserID :: IO UserID
`getRealUserID' calls `geteuid' to obtain the effective `UserID' associated with the current process.
setUserID :: UserID -> IO ()
`setUserID uid' calls `setuid' to set the real, effective, and saved set-user-id associated with the current process to `uid'.
getLoginName :: IO String
`getLoginName' calls `getlogin' to obtain the login name associated with the current process.
getRealGroupID :: IO GroupID
`getRealGroupID' calls `getgid' to obtain the real `GroupID' associated with the current process.
getEffectiveGroupID :: IO GroupID
`getEffectiveGroupID' calls `getegid' to obtain the effective `GroupID' associated with the current process.
setGroupID :: GroupID -> IO ()
`setGroupID gid' calls `setgid' to set the real, effective, and saved set-group-id associated with the current process to `gid'.
getGroups :: IO [GroupID]
`getGroups' calls `getgroups' to obtain the list of supplementary `GroupID's associated with the current process.
getEffectiveUserName :: IO String
`getEffectiveUserName' calls `cuserid' to obtain a name associated with the effective `UserID' of the process.
getProcessGroupID :: IO ProcessGroupID
`getProcessGroupID' calls `getpgrp' to obtain the `ProcessGroupID' for the current process.
createProcessGroup :: ProcessID -> IO ProcessGroupID
`createProcessGroup pid' calls `setpgid' to make process `pid' a new process group leader.
joinProcessGroup :: ProcessGroupID -> IO ProcessGroupID
`joinProcessGroup pgid' calls `setpgid' to set the `ProcessGroupID' of the current process to `pgid'.
setProcessGroupID :: ProcessID -> ProcessGroupID -> IO ()
`setProcessGroupID pid pgid' calls `setpgid' to set the `ProcessGroupID' for process `pid' to `pgid'.
createSession :: IO ProcessGroupID
`createSession' calls `setsid' to create a new session with the current process as session leader.
systemName :: SystemID -> String nodeName :: SystemID -> String release :: SystemID -> String version :: SystemID -> String machine :: SystemID -> String getSystemID :: IO SystemID
`getSystemID' calls `uname' to obtain information about the current operating system.
> epochTime :: IO EpochTime
`epochTime' calls `time' to obtain the number of seconds that have elapsed since the epoch (Jan 01 00:00:00 GMT 1970).
elapsedTime :: ProcessTimes -> ClockTick userTime :: ProcessTimes -> ClockTick systemTime :: ProcessTimes -> ClockTick childUserTime :: ProcessTimes -> ClockTick childSystemTime :: ProcessTimes -> ClockTick getProcessTimes :: IO ProcessTimes
`getProcessTimes' calls `times' to obtain time-accounting information for the current process and its children.
getControllingTerminalName :: IO FilePath
`getControllingTerminalName' calls `ctermid' to obtain a name associated with the controlling terminal for the process. If a controlling terminal exists, `getControllingTerminalName' returns the name of the controlling terminal.
The operation may fail with:
getTerminalName :: Fd -> IO FilePath
`getTerminalName fd' calls `ttyname' to obtain a name associated with the terminal for `Fd' `fd'. If `fd' is associated with a terminal, `getTerminalName' returns the name of the terminal.
The operation may fail with:
queryTerminal :: Fd -> IO Bool
`queryTerminal fd' calls `isatty' to determine whether or not `Fd' `fd' is associated with a terminal.
getSysVar :: SysVar -> IO Limit
`getSysVar var' calls `sysconf' to obtain the dynamic value of the requested configurable system limit or option. For defined system limits, `getSysVar' returns the associated value. For defined system options, the result of `getSysVar' is undefined, but not failure.
The operation may fail with:
openDirStream :: FilePath -> IO DirStream
`openDirStream dir' calls `opendir' to obtain a directory stream for `dir'.
readDirStream :: DirStream -> IO String
`readDirStream dp' calls `readdir' to obtain the next directory entry (`struct dirent') for the open directory stream `dp', and returns the `d_name' member of that structure.
The operation may fail with:
rewindDirStream :: DirStream -> IO ()
`rewindDirStream dp' calls `rewinddir' to reposition the directory stream `dp' at the beginning of the directory.
closeDirStream :: DirStream -> IO ()
`closeDirStream dp' calls `closedir' to close the directory stream `dp'.
getWorkingDirectory :: IO FilePath
`getWorkingDirectory' calls `getcwd' to obtain the name of the current working directory.
changeWorkingDirectory :: FilePath -> IO ()
`changeWorkingDirectory dir' calls `chdir' to change the current working directory to `dir'.
nullFileMode :: FileMode -- --------- ownerReadMode :: FileMode -- r-------- ownerWriteMode :: FileMode -- -w------- ownerExecuteMode :: FileMode -- --x------ groupReadMode :: FileMode -- --r----- groupWriteMode :: FileMode -- ----w---- groupExecuteMode :: FileMode -- -----x--- otherReadMode :: FileMode -- ------r-- otherWriteMode :: FileMode -- -------w- otherExecuteMode :: FileMode -- --------x setUserIDMode :: FileMode -- --S------ setGroupIDMode :: FileMode -- -----S--- stdFileMode :: FileMode -- rw-rw-rw- ownerModes :: FileMode -- rwx------ groupModes :: FileMode -- --rwx--- otherModes :: FileMode -- ------rwx accessModes :: FileMode -- rwxrwxrwx unionFileModes :: FileMode -> FileMode -> FileMode intersectFileModes :: FileMode -> FileMode -> FileMode stdInput :: Fd stdInput = intToFd 0 stdOutput :: Fd stdOutput = intToFd 1 stdError :: Fd stdError = intToFd 2 data OpenFileFlags = OpenFileFlags { append :: Bool, exclusive :: Bool, noctty :: Bool, nonBlock :: Bool, trunc :: Bool } openFd :: FilePath -> OpenMode -> Maybe FileMode -- Just x => O_CREAT, Nothing => must exist -> OpenFileFlags -> IO Fd
`openFd path acc mode (OpenFileFlags app excl noctty nonblock trunc)' calls `open' to obtain a `Fd' for the file `path' with access mode `acc'. If `mode' is `Just m', the `O_CREAT' flag is set and the file's permissions will be based on `m' if it does not already exist; otherwise, the `O_CREAT' flag is not set. The arguments `app', `excl', `noctty', `nonblock', and `trunc' control whether or not the flags `O_APPEND', `O_EXCL', `O_NOCTTY', `O_NONBLOCK', and `O_TRUNC' are set, respectively.
createFile :: FilePath -> FileMode -> IO Fd
`createFile path mode' calls `creat' to obtain a `Fd' for file `path', which will be created with permissions based on `mode' if it does not already exist.
setFileCreationMask :: FileMode -> IO FileMode
`setFileCreationMask mode' calls `umask' to set the process's file creation mask to `mode'. The previous file creation mask is returned.
createLink :: FilePath -> FilePath -> IO ()
`createLink old new' calls `link' to create a new path, `new', linked to an existing file, `old'.
createDirectory :: FilePath -> FileMode -> IO ()
`createDirectory dir mode' calls `mkdir' to create a new directory, `dir', with permissions based on `mode'.
createNamedPipe :: FilePath -> FileMode -> IO ()
`createNamedPipe fifo mode' calls `mkfifo' to create a new named pipe, `fifo', with permissions based on `mode'.
removeLink :: FilePath -> IO ()
`removeLink path' calls `unlink' to remove the link named `path'.
removeDirectory :: FilePath -> IO ()
`removeDirectory dir' calls `rmdir' to remove the directory named `dir'.
rename :: FilePath -> FilePath -> IO ()
`rename old new' calls `rename' to rename a file or directory from `old' to `new'.
fileMode :: FileStatus -> FileMode fileID :: FileStatus -> FileID deviceID :: FileStatus -> DeviceID linkCount :: FileStatus -> LinkCount fileOwner :: FileStatus -> UserID fileGroup :: FileStatus -> GroupID fileSize :: FileStatus -> FileOffset accessTime :: FileStatus -> EpochTime modificationTime :: FileStatus -> EpochTime statusChangeTime :: FileStatus -> EpochTime isDirectory :: FileStatus -> Bool isCharacterDevice :: FileStatus -> Bool isBlockDevice :: FileStatus -> Bool isRegularFile :: FileStatus -> Bool isNamedPipe :: FileStatus -> Bool getFileStatus :: FilePath -> IO FileStatus
`getFileStatus path' calls `stat' to get the `FileStatus' information for the file `path'.
getFdStatus :: Fd -> IO FileStatus
`getFdStatus fd' calls `fstat' to get the `FileStatus' information for the file associated with `Fd' `fd'.
queryAccess :: FilePath -> Bool -> Bool -> Bool -> IO Bool
`queryAccess path r w x' calls `access' to test the access permissions for file `path'. The three arguments, `r', `w', and `x' control whether or not `access' is called with `R_OK', `W_OK', and `X_OK' respectively.
queryFile :: FilePath -> IO Bool
`queryFile path' calls `access' with `F_OK' to test for the existence for file `path'.
setFileMode :: FilePath -> FileMode -> IO ()
`setFileMode path mode' calls `chmod' to set the permission bits associated with file `path' to `mode'.
setOwnerAndGroup :: FilePath -> UserID -> GroupID -> IO ()
`setOwnerAndGroup path uid gid' calls `chown' to set the `UserID' and `GroupID' associated with file `path' to `uid' and `gid', respectively.
setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO ()
`setFileTimes path atime mtime' calls `utime' to set the access and modification times associated with file `path' to `atime' and `mtime', respectively.
touchFile :: FilePath -> IO ()
`touchFile path' calls `utime' to set the access and modification times associated with file `path' to the current time.
getPathVar :: PathVar -> FilePath -> IO Limit
`getPathVar var path' calls `pathconf' to obtain the dynamic value of the requested configurable file limit or option associated with file or directory `path'. For defined file limits, `getPathVar' returns the associated value. For defined file options, the result of `getPathVar' is undefined, but not failure. The operation may fail with:
getFdVar :: PathVar -> Fd -> IO Limit
`getFdVar var fd' calls `fpathconf' to obtain the dynamic value of the requested configurable file limit or option associated with the file or directory attached to the open channel `fd'. For defined file limits, `getFdVar' returns the associated value. For defined file options, the result of `getFdVar' is undefined, but not failure.
The operation may fail with:
createPipe :: IO (Fd, Fd)
`createPipe' calls `pipe' to create a pipe and returns a pair of `Fd's, the first for writing and the second for reading.
dup :: Fd -> IO Fd
`dup fd' calls `dup' to duplicate `Fd' `fd' to another `Fd'.
dupTo :: Fd -> Fd -> IO ()
`dupTo src dst' calls `dup2' to duplicate `Fd' `src' to `Fd' `dst'.
fdClose :: Fd -> IO ()
`fdClose fd' calls `close' to close `Fd' `fd'.
fdRead :: Fd -> ByteCount -> IO (String, ByteCount)
`fdRead fd nbytes' calls `read' to read at most `nbytes' bytes from `Fd' `fd', and returns the result as a string paired with the number of bytes actually read.
The operation may fail with:
fdWrite :: Fd -> String -> IO ByteCount
`fdWrite fd s' calls `write' to write the string `s' to `Fd' `fd' as a contiguous sequence of bytes. It returns the number of bytes successfully written.
queryFdOption :: FdOption -> Fd -> IO Bool
`getFdOption opt fd' calls `fcntl' to determine whether or not the flag associated with `FdOption' `opt' is set for `Fd' `fd'.
setFdOption :: Fd -> FdOption -> Bool -> IO ()
`setFdOption fd opt val' calls `fcntl' to set the flag associated with `FdOption' `opt' on `Fd' `fd' to `val'.
getLock :: Fd -> FileLock -> IO (Maybe (ProcessID, FileLock))
`getLock fd lock' calls `fcntl' to get the first `FileLock' for `Fd' `fd' which blocks the `FileLock' `lock'. If no such `FileLock' exists, `getLock' returns `Nothing'. Otherwise, it returns `Just (pid, block)', where `block' is the blocking `FileLock' and `pid' is the `ProcessID' of the process holding the blocking `FileLock'.
setLock :: Fd -> FileLock -> IO ()
`setLock fd lock' calls `fcntl' with `F_SETLK' to set or clear a lock segment for `Fd' `fd' as indicated by the `FileLock' `lock'. `setLock' does not block, but fails with `SystemError' if the request cannot be satisfied immediately.
waitToSetLock :: Fd -> FileLock -> IO ()
`waitToSetLock fd lock' calls `fcntl' with `F_SETLKW' to set or clear a lock segment for `Fd' `fd' as indicated by the `FileLock' `lock'. If the request cannot be satisfied immediately, `waitToSetLock' blocks until the request can be satisfied.
fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset
`fdSeek fd whence offset' calls `lseek' to position the `Fd' `fd' at the given `offset' from the starting location indicated by `whence'. It returns the resulting offset from the start of the file in bytes.
terminalMode :: TerminalMode -> TerminalAttributes -> Bool withMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes withoutMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes bitsPerByte :: TerminalAttributes -> Int withBits :: TerminalAttributes -> Int -> TerminalAttributes controlChar :: TerminalAttributes -> ControlCharacter -> Maybe Char withCC :: TerminalAttributes -> (ControlCharacter, Char) -> TerminalAttributes withoutCC :: TerminalAttributes -> ControlCharacter -> TerminalAttributes inputTime :: TerminalAttributes -> Int withTime :: TerminalAttributes -> Int -> TerminalAttributes minInput :: TerminalAttributes -> Int withMinInput :: TerminalAttributes -> Int -> TerminalAttributes inputSpeed :: TerminalAttributes -> BaudRate withInputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes outputSpeed :: TerminalAttributes -> BaudRate withOutputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes getTerminalAttributes :: Fd -> IO TerminalAttributes
`getTerminalAttributes fd' calls `tcgetattr' to obtain the `TerminalAttributes' associated with `Fd' `fd'.
setTerminalAttributes :: Fd -> TerminalAttributes -> TerminalState -> IO ()
`setTerminalAttributes fd attr ts' calls `tcsetattr' to change the `TerminalAttributes' associated with `Fd' `fd' to `attr', when the terminal is in the state indicated by `ts'.
sendBreak :: Fd -> Int -> IO ()
`sendBreak fd duration' calls `tcsendbreak' to transmit a continuous stream of zero-valued bits on `Fd' `fd' for the specified implementation-dependent `duration'.
drainOutput :: Fd -> IO ()
`drainOutput fd' calls `tcdrain' to block until all output written to `Fd' `fd' has been transmitted.
discardData :: Fd -> QueueSelector -> IO ()
`discardData fd queues' calls `tcflush' to discard pending input and/or output for `Fd' `fd', as indicated by the `QueueSelector' `queues'.
controlFlow :: Fd -> FlowAction -> IO ()
`controlFlow fd action' calls `tcflow' to control the flow of data on `Fd' `fd', as indicated by `action'.
getTerminalProcessGroupID :: Fd -> IO ProcessGroupID
`getTerminalProcessGroupID fd' calls `tcgetpgrp' to obtain the `ProcessGroupID' of the foreground process group associated with the terminal attached to `Fd' `fd'.
setTerminalProcessGroupID :: Fd -> ProcessGroupID -> IO ()
`setTerminalProcessGroupID fd pgid' calls `tcsetpgrp' to set the `ProcessGroupID' of the foreground process group associated with the terminal attached to `Fd' `fd' to `pgid'.
groupName :: GroupEntry -> String groupID :: GroupEntry -> GroupID groupMembers :: GroupEntry -> [String] getGroupEntryForID :: GroupID -> IO GroupEntry
`getGroupEntryForID gid' calls `getgrgid' to obtain the `GroupEntry' information associated with `GroupID' `gid'.
The operation may fail with:
getGroupEntryForName :: String -> IO GroupEntry
`getGroupEntryForName name' calls `getgrnam' to obtain the `GroupEntry' information associated with the group called `name'.
The operation may fail with:
userName :: UserEntry -> String userID :: UserEntry -> UserID userGroupID :: UserEntry -> GroupID homeDirectory :: UserEntry -> String userShell :: UserEntry -> String getUserEntryForID :: UserID -> IO UserEntry
`getUserEntryForID gid' calls `getpwuid' to obtain the `UserEntry' information associated with `UserID' `uid'. The operation may fail with:
getUserEntryForName :: String -> IO UserEntry
`getUserEntryForName name' calls `getpwnam' to obtain the `UserEntry' information associated with the user login `name'.
The operation may fail with:
getErrorCode :: IO ErrorCode
`getErrorCode' returns the current value of the external variable `errno'. It never fails.
setErrorCode :: ErrorCode -> IO ()
`setErrorCode err' sets the external variable `errno' to `err'. It never fails.
noError :: ErrorCode noError = 0 argumentListTooLong, e2BIG :: ErrorCode badFd, eBADF :: ErrorCode brokenPipe, ePIPE :: ErrorCode directoryNotEmpty, eNOTEMPTY :: ErrorCode execFormatError, eNOEXEC :: ErrorCode fileAlreadyExists, eEXIST :: ErrorCode fileTooLarge, eFBIG :: ErrorCode filenameTooLong, eNAMETOOLONG :: ErrorCode improperLink, eXDEV :: ErrorCode inappropriateIOControlOperation, eNOTTY :: ErrorCode inputOutputError, eIO :: ErrorCode interruptedOperation, eINTR :: ErrorCode invalidArgument, eINVAL :: ErrorCode invalidSeek, eSPIPE :: ErrorCode isADirectory, eISDIR :: ErrorCode noChildProcess, eCHILD :: ErrorCode noLocksAvailable, eNOLCK :: ErrorCode noSpaceLeftOnDevice, eNOSPC :: ErrorCode noSuchOperationOnDevice, eNODEV :: ErrorCode noSuchDeviceOrAddress, eNXIO :: ErrorCode noSuchFileOrDirectory, eNOENT :: ErrorCode noSuchProcess, eSRCH :: ErrorCode notADirectory, eNOTDIR :: ErrorCode notEnoughMemory, eNOMEM :: ErrorCode operationNotImplemented, eNOSYS :: ErrorCode operationNotPermitted, ePERM :: ErrorCode permissionDenied, eACCES :: ErrorCode readOnlyFileSystem, eROFS :: ErrorCode resourceBusy, eBUSY :: ErrorCode resourceDeadlockAvoided, eDEADLK :: ErrorCode resourceTemporarilyUnavailable, eAGAIN :: ErrorCode tooManyLinks, eMLINK :: ErrorCode tooManyOpenFiles, eMFILE :: ErrorCode tooManyOpenFilesInSystem, eNFILE :: ErrorCode
This documentation is stolen directly from the HBC distribution. The modules that GHC does not support (because they require HBC-specific extensions) are omitted.
data Either a b = Left a | Right bThe constructor `Left' is typically used for errors; it can be renamed to `Wrong' on import.
data Maybe a = Nothing | Just a thenM :: Maybe a -> (a -> Maybe b) -> Maybe b -- apply a function that may fail
data Option a = None | Some a thenO :: Option a -> (a -> Option b) -> Option b
assoc :: (Eq c) => (a -> b) -> b -> [(c, a)] -> c -> b -- assoc f d l k looks for k in the association list l, if it -- is found f is applied to the value, otherwise d is returned. concatMap :: (a -> [b]) -> [a] -> [b] -- flattening map (LML's concmap) unfoldr :: (a -> (b, a)) -> (a -> Bool) -> a -> [b] -- unfoldr f p x repeatedly applies f to x until (p x) holds. -- (f x) should give a list element and a new x. mapAccuml :: (a -> b -> (a, c)) -> a -> [b] -> (a, [c]) -- mapAccuml f s l maps f over l, but also threads the state s -- through (LML's mapstate). union :: (Eq a) => [a] -> [a] -> [a] -- union of two lists intersection :: (Eq a) => [a] -> [a] -> [a] -- intersection of two lists chopList :: ([a] -> (b, [a])) -> [a] -> [b] -- LMLs choplist assocDef :: (Eq a) => [(a, b)] -> b -> a -> b -- LMLs assocdef lookup :: (Eq a) => [(a, b)] -> a -> Option b -- lookup l k looks for the key k in the association list l -- and returns an optional value tails :: [a] -> [[a]] -- return all the tails of a list rept :: (Integral a) => a -> b -> [b] -- repeat a value a number of times groupEq :: (a->a->Bool) -> [a] -> [[a]] -- group list elements according to an equality predicate group :: (Eq a) => [a] -> [[a]] -- group according to} == readListLazily :: (Text a) => String -> [a] -- read a list in a lazy fashion
type Context = (Bool, Int, Int, Int) type IText = Context -> [String] text :: String -> IText -- just text (~.) :: IText -> IText -> IText -- horizontal composition (^.) :: IText -> IText -> IText -- vertical composition separate :: [IText] -> IText -- separate by spaces nest :: Int -> IText -> IText -- indent pretty :: Int -> Int -> IText -> String -- format it
sortLe :: (a -> a -> Bool) -> [a] -> [a] -- sort le l sorts l with le as less than predicate sort :: (Ord a) => [a] -> [a] -- sort l sorts l using the Ord class
randomInts :: Int -> Int -> [Int] -- given two seeds gives a list of random Int randomDoubles :: Int -> Int -> [Double] -- random Double with uniform distribution in (0,1) normalRandomDoubles :: Int -> Int -> [Double] -- random Double with normal distribution, mean 0, variance 1
trace :: String -> a -> a -- trace x y prints x and returns y
class Bits a where bitAnd :: a -> a -> a -- bitwise and bitOr :: a -> a -> a -- bitwise or bitXor :: a -> a -> a -- bitwise xor bitCompl :: a -> a -- bitwise negation bitRsh :: a -> Int -> a -- bitwise right shift bitLsh :: a -> Int -> a -- bitwise left shift bitSwap :: a -> a -- swap word halves bit0 :: a -- word with least significant bit set bitSize :: a -> Int -- number of bits in a word data Byte -- 8 bit quantity data Short -- 16 bit quantity data Word -- 32 bit quantity instance Bits Byte, Bits Short, Bits Word instance Eq Byte, Eq Short, Eq Word instance Ord Byte, Ord Short, Ord Word instance Text Byte, Text Short, Text Word instance Num Byte, Num Short, Num Word wordToShorts :: Word -> [Short] -- convert a Word to two Short wordToBytes :: Word -> [Byte] -- convert a Word to four Byte bytesToString :: [Byte] -> String -- convert a list of Byte to a String (bit by bit) wordToInt :: Word -> Int -- convert a Word to Int shortToInt :: Short -> Int -- convert a Short to Int byteToInt :: Byte -> Int -- convert a Byte to Int
-- year mon day hour min sec dec-sec weekday data Time = Time Int Int Int Int Int Int Double Int dblToTime :: Double -> Time -- convert a Double to a Time timeToDbl :: Time -> Double -- convert a Time to a Double timeToString :: Time -> String -- convert a Time to a readable String
class Hashable a where hash :: a -> Int -- hash a value, return an Int -- instances for all Prelude types hashToMax :: (Hashable a) => Int -> a -> Int -- hash into interval [0..x-1]
type Name = Int initialNameSupply :: NameSupply -- The initial name supply (may be different every -- time the program is run. splitNameSupply :: NameSupply -> (NameSupply,NameSupply) -- split the namesupply into two getName :: NameSupply -> Name -- get the name associated with a name supply
infixr 8 +.+ , ..+ , +.. infix 6 `act` , >>> , `into` , .> infixr 4 ||| , ||! , |!! data ParseResult a b type Parser a b = a -> Int -> ParseResult a b (|||) :: Parser a b -> Parser a b -> Parser a b -- Alternative (||!) :: Parser a b -> Parser a b -> Parser a b -- Alternative, but with committed choice (|!!) :: Parser a b -> Parser a b -> Parser a b -- Alternative, but with committed choice (+.+) :: Parser a b -> Parser a c -> Parser a (b,c) -- Sequence (..+) :: Parser a b -> Parser a c -> Parser a c -- Sequence, throw away first part (+..) :: Parser a b -> Parser a c -> Parser a b -- Sequence, throw away second part act :: Parser a b -> (b->c) -> Parser a c -- Action (>>>) :: Parser a (b,c) -> (b->c->d) -> Parser a d -- Action on two items (.>) :: Parser a b -> c -> Parse a c -- Action ignoring value into :: Parser a b -> (b -> Parser a c) -> Parser a c -- Use a produced value in a parser. succeed b :: Parser a b -- Always succeeds without consuming a token failP :: Parser a b -- Always fails. many :: Parser a b -> Parser a [b] -- Kleene star many1 :: Parser a b -> Parser a [b] -- Kleene plus count :: Parser a b -> Int -> Parser a [b] -- Parse an exact number of items sepBy1 :: Parser a b -> Parser a c -> Parser a [b] -- Non-empty sequence of items separated by something sepBy :: Parser a b -> Parser a c -> Parser a [b] -- Sequence of items separated by something lit :: (Eq a, Text a) => a -> Parser [a] a -- Recognise a literal token from a list of tokens litp :: String -> (a->Bool) -> Parser [a] a -- Recognise a token with a predicate. -- The string is a description for error messages. testp :: String -> (a -> Bool) -> (Parser b a) -> Parser b a -- Test a semantic value. token :: (a -> Either String (b, a)) -> Parser a b -- General token recogniser. parse :: Parser a b -> a -> Either ([String], a) [(b, a)] -- Do a parse. Return either error (possible tokens and rest -- of tokens) or all possible parses. sParse :: (Text a) => (Parser [a] b) -> [a] -> Either String b -- Simple parse. Return error message or result.
type Bytes = [Char] -- A byte stream is just a list of characters class Native a where showBytes :: a -> Bytes -> Bytes -- prepend the representation of an item the a byte stream listShowBytes :: [a] -> Bytes -> Bytes -- prepend the representation of a list of items to a stream -- (may be more efficient than repeating showBytes). readBytes :: Bytes -> Maybe (a, Bytes) -- get an item from the stream and return the rest, -- or fail if the stream is to short. listReadBytes :: Int -> Bytes -> Maybe ([a], Bytes) -- read n items from a stream. instance Native Int instance Native Float instance Native Double instance (Native a, Native b) => Native (a,b) -- juxtaposition of the two items instance (Native a, Native b, Native c) => Native (a, b, c) -- juxtaposition of the three items instance (Native a) => Native [a] -- an item count in an Int followed by the items shortIntToBytes :: Int -> Bytes -> Bytes -- Convert an Int to what corresponds to a short in C. bytesToShortInt :: Bytes -> Maybe (Int, Bytes) -- Get a short from a byte stream and convert to an Int. showB :: (Native a) => a -> Bytes -- Simple interface to showBytes. readB :: (Native a) => Bytes -> a -- Simple interface to readBytes.
data Number -- The type itself. instance ... -- All reasonable instances. isInteger :: Number -> Bool -- Test if a Number is an integer.
Concurrent and Parallel Haskell are Glasgow extensions to Haskell which let you structure your program as a group of independent `threads'.
Concurrent and Parallel Haskell have very different purposes.
Concurrent Haskell is for applications which have an inherent structure of interacting, concurrent tasks (i.e. `threads'). Threads in such programs may be required. For example, if a concurrent thread has been spawned to handle a mouse click, it isn't optional -- the user wants something done!
A Concurrent Haskell program implies multiple `threads' running within a single Unix process on a single processor.
You will find at least one paper about Concurrent Haskell hanging off of Simon Peyton Jones's Web page; `http://www.dcs.gla.ac.uk/~simonpj/'.
Parallel Haskell is about speed -- spawning threads onto multiple processors so that your program will run faster. The `threads' are always advisory -- if the runtime system thinks it can get the job done more quickly by sequential execution, then fine.
A Parallel Haskell program implies multiple processes running on multiple processors, under a PVM (Parallel Virtual Machine) framework.
Parallel Haskell is still relatively new; it is more about "research fun" than about "speed." That will change.
Again, check Simon's Web page for publications about Parallel Haskell (including "GUM", the key bits of the runtime system).
Some details about Concurrent and Parallel Haskell follow.
GHC provides a `Concurrent' module, a common interface to a collection of useful concurrency abstractions, including those mentioned in the "concurrent paper".
Just put `import Concurrent' into your modules, and away you go. To create a "required thread":
forkIO :: IO a -> IO a
The `Concurrent' interface also provides access to "I-Vars" and "M-Vars", which are two flavours of synchronising variables.
`IVars' are write-once
variables. They start out empty, and any threads that attempt to read
them will block until they are filled. Once they are written, any
blocked threads are freed, and additional reads are permitted.
Attempting to write a value to a full `IVar' results in a runtime
error. Interface:
newIVar :: IO (IVar a) readIVar :: IVar a -> IO a writeIVar :: IVar a -> a -> IO ()
`MVars' are rendezvous points,
mostly for concurrent threads. They begin empty, and any attempt to
read an empty `MVar' blocks. When an `MVar' is written, a
single blocked thread may be freed. Reading an `MVar' toggles its
state from full back to empty. Therefore, any value written to an
`MVar' may only be read once. Multiple reads and writes are
allowed, but there must be at least one read between any two
writes. Interface:
newEmptyMVar :: IO (MVar a) newMVar :: a -> IO (MVar a) takeMVar :: MVar a -> IO a putMVar :: MVar a -> a -> IO () readMVar :: MVar a -> IO a swapMVar :: MVar a -> a -> IO a
A channel variable (`CVar') is a one-element channel, as described in the paper:
data CVar a newCVar :: IO (CVar a) putCVar :: CVar a -> a -> IO () getCVar :: CVar a -> IO a
A `Channel' is an unbounded channel:
data Chan a newChan :: IO (Chan a) putChan :: Chan a -> a -> IO () getChan :: Chan a -> IO a dupChan :: Chan a -> IO (Chan a) unGetChan :: Chan a -> a -> IO () getChanContents :: Chan a -> IO [a]
General and quantity semaphores:
data QSem newQSem :: Int -> IO QSem waitQSem :: QSem -> IO () signalQSem :: QSem -> IO () data QSemN newQSemN :: Int -> IO QSemN signalQSemN :: QSemN -> Int -> IO () waitQSemN :: QSemN -> Int -> IO ()
Merging streams -- binary and n-ary:
mergeIO :: [a] -> [a] -> IO [a] nmergeIO :: [[a]] -> IO [a]
A Sample variable (`SampleVar') is slightly different from a normal `MVar':
type SampleVar a = MVar (Int, MVar a) emptySampleVar :: SampleVar a -> IO () newSampleVar :: IO (SampleVar a) readSample :: SampleVar a -> IO a writeSample :: SampleVar a -> a -> IO ()
Finally, there are operations to delay a concurrent thread, and to make one wait:
threadDelay :: Int -> IO () -- delay rescheduling for N microseconds threadWaitRead :: Int -> IO () -- wait for input on specified file descriptor threadWaitWrite :: Int -> IO () -- (read and write, respectively).
GHC provides two functions for controlling parallel execution, through
the `Parallel' interface:
interface Parallel where infixr 0 `par` infixr 1 `seq` par :: a -> b -> b seq :: a -> b -> b
The expression `(x `par` y)' sparks the evaluation of `x' (to weak head normal form) and returns `y'. Sparks are queued for execution in FIFO order, but are not executed immediately. At the next heap allocation, the currently executing thread will yield control to the scheduler, and the scheduler will start a new thread (until reaching the active thread limit) for each spark which has not already been evaluated to WHNF.
The expression `(x `seq` y)' evaluates `x' to weak head normal form and then returns `y'. The `seq' primitive can be used to force evaluation of an expression beyond WHNF, or to impose a desired execution sequence for the evaluation of an expression.
For example, consider the following parallel version of our old nemesis, `nfib':
import Parallel nfib :: Int -> Int nfib n | n <= 1 = 1 | otherwise = par n1 (seq n2 (n1 + n2 + 1)) where n1 = nfib (n-1) n2 = nfib (n-2)
For values of `n' greater than 1, we use `par' to spark a thread to evaluate `nfib (n-1)', and then we use `seq' to force the parent thread to evaluate `nfib (n-2)' before going on to add together these two subexpressions. In this divide-and-conquer approach, we only spark a new thread for one branch of the computation (leaving the parent to evaluate the other branch). Also, we must use `seq' to ensure that the parent will evaluate `n2' before `n1' in the expression `(n1 + n2 + 1)'. It is not sufficient to reorder the expression as `(n2 + n1 + 1)', because the compiler may not generate code to evaluate the addends from left to right.
The functions `par' and `seq' are wired into GHC, and unfold into uses of the `par#' and `seq#' primitives, respectively. If you'd like to see this with your very own eyes, just run GHC with the `-ddump-simpl' option. (Anything for a good time...)
You can use `par' and `seq' in Concurrent Haskell, though I'm not sure why you would want to.
Actually, you can use the ``par`' and ``seq`' combinators (really for Parallel Haskell) in Concurrent Haskell as well. But doing things like "`par' to `forkIO' many required threads" counts as "jumping out the 9th-floor window, just to see what happens."
Runnable threads are scheduled in round-robin fashion. Context switches are signalled by the generation of new sparks or by the expiry of a virtual timer (the timer interval is configurable with the `-C[<num>]' RTS option). However, a context switch doesn't really happen until the next heap allocation. If you want extremely short time slices, the `-C' RTS option can be used to force a context switch at each and every heap allocation.
When a context switch occurs, pending sparks which have not already been reduced to weak head normal form are turned into new threads. However, there is a limit to the number of active threads (runnable or blocked) which are allowed at any given time. This limit can be adjusted with the `-t<num>' RTS option (the default is 32). Once the thread limit is reached, any remaining sparks are deferred until some of the currently active threads are completed.
[You won't get far unless your GHC system was configured/built with concurrency and/or parallelism enabled. (They require separate library modules.) The relevant section of the installation guide says how to do this.]
To compile a program as Concurrent Haskell, use the `-concurrent' option, both when compiling and linking. You will probably need the `-fglasgow-exts' option, too.
Three RTS options are provided for modifying the behaviour of the threaded runtime system. See the descriptions of `-C[<us>]', `-q', and `-t<num>' in Section 11.2.7 RTS options for Concurrent/Parallel Haskell.
The main thread in a Concurrent Haskell program is given its own private stack space, but all other threads are given stack space from the heap. Stack space for the main thread can be adjusted as usual with the `-K' RTS option, but if this private stack space is exhausted, the main thread will switch to stack segments in the heap, just like any other thread. Thus, problems which would normally result in stack overflow in "sequential Haskell" can be expected to result in heap overflow when using threads.
The concurrent runtime system uses black holes as synchronisation points for subexpressions which are shared among multiple threads. In "sequential Haskell", a black hole indicates a cyclic data dependency, which is a fatal error. However, in concurrent execution, a black hole may simply indicate that the desired expression is being evaluated by another thread. Therefore, when a thread encounters a black hole, it simply blocks and waits for the black hole to be updated. Cyclic data dependencies will result in deadlock, and the program will fail to terminate.
Because the concurrent runtime system uses black holes as synchronisation points, it is not possible to disable black-holing with the `-N' RTS option. Therefore, the use of signal handlers (including timeouts) with the concurrent runtime system can lead to problems if a thread attempts to enter a black hole that was created by an abandoned computation. The use of signal handlers in conjunction with threads is strongly discouraged.
[You won't be able to execute parallel Haskell programs unless PVM3 (Parallel Virtual Machine, version 3) is installed at your site.]
To compile a Haskell program for parallel execution under PVM, use the `-parallel' option, both when compiling and linking. You will probably want to `import Parallel' into your Haskell modules.
To run your parallel program, once PVM is going, just invoke it "as normal". The main extra RTS option is `-N<n>', to say how many PVM "processors" your program to run on. (For more details of all relevant RTS options, please see section 11.2.7 RTS options for Concurrent/Parallel Haskell.)
In truth, running Parallel Haskell programs and getting information out of them (e.g., parallelism profiles) is a battle with the vagaries of PVM, detailed in the following sections.
Before you can run a parallel program under PVM, you must set the
required environment variables (PVM's idea, not ours); something like,
probably in your `.cshrc' or equivalent:
setenv PVM_ROOT /wherever/you/put/it setenv PVM_ARCH `$PVM_ROOT/lib/pvmgetarch` setenv PVM_DPATH $PVM_ROOT/lib/pvmd
Creating and/or controlling your "parallel machine" is a purely-PVM business; nothing specific to Parallel Haskell.
You use the `pvm' command to start PVM on your machine. You can then do various things to control/monitor your "parallel machine;" the most useful being:
`Control-D' exit `pvm', leaving it running `halt' kill off this "parallel machine" & exit `add <host>' add `<host>' as a processor `delete <host>' delete `<host>' `reset' kill what's going, but leave PVM up `conf' list the current configuration `ps' report processes' status `pstat <pid>' status of a particular process
The PVM documentation can tell you much, much more about `pvm'!
With Parallel Haskell programs, we usually don't care about the results -- only with "how parallel" it was! We want pretty pictures.
Parallelism profiles (a la `hbcpp') can be generated with the `-q' RTS option. The per-processor profiling info is dumped into files named `<full-path><program>.gr'. These are then munged into a PostScript picture, which you can then display. For example, to run your program `a.out' on 8 processors, then view the parallelism profile, do:
% ./a.out +RTS -N8 -q % grs2gr *.???.gr > temp.gr # combine the 8 .gr files into one % gr2ps -O temp.gr # cvt to .ps; output in temp.ps % ghostview -seascape temp.ps # look at it!
The scripts for processing the parallelism profiles are distributed in `ghc/utils/parallel/'.
The "garbage-collection statistics" RTS options can be useful for seeing what parallel programs are doing. If you do either `+RTS -Sstderr' or `+RTS -sstderr', then you'll get mutator, garbage-collection, etc., times on standard error. The standard error of all PE's other than the `main thread' appears in `/tmp/pvml.nnn', courtesy of PVM.
Whether doing `+RTS -Sstderr' or not, a handy way to watch what's happening overall is: `tail -f /tmp/pvml.nnn'.
Besides the usual runtime system (RTS) options (section 5 Controlling the run-time behaviour of your programs), there are a few options particularly for concurrent/parallel execution.
The "Potential problems" for Concurrent Haskell also apply for Parallel Haskell. Please see Section 11.2.2 Potential problems with Concurrent Haskell.
If you still have a problem after consulting this section, then you may have found a bug -- please report it! See Section 12.3 How to report a bug in the GHC system for a list of things we'd like to know about your bug. If in doubt, send a report -- we love mail from irate users :-!
(Section 14 Haskell 1.3 vs. Glasgow Haskell 2.02: language non-compliance, which describes Glasgow Haskell's shortcomings vs. the Haskell language definition, may also be of interest.)
(For advice about overly slow or memory-hungry Haskell programs, please see section 6 Advice on: sooner, faster, smaller, stingier).
% rm *.o # scrub your object files % make my_prog # re-make your program; use -hi-diffs to highlight changes; # as mentioned above, use -dcore-lint to be more paranoid % ./my_prog ... # retry...Of course, if you have `_ccall_'s/`_casm_'s in your program then all bets are off, because you can trash the heap, the stack, or whatever. If you are interested in hard-core debugging of a crashing GHC-compiled program, please see section 12.4 Hard-core debugging of GHC-compiled programs.
Glasgow Haskell is a changing system so there are sure to be bugs in it. Please report them to `glasgow-haskell-bugs@dcs.gla.ac.uk'! (However, please check the earlier part of this section to be sure it's not a known not-really-a problem.)
The name of the bug-reporting game is: facts, facts, facts. Don't omit them because "Oh, they won't be interested..."
If your program is crashing, you should almost surely file a bug report, as outlined in previous sections.
This section suggests ways to Make Further Progress Anyway.
The first thing to establish is: Is it a garbage-collection (GC) bug? Try your program with a very large heap and a `-Sstderr' RTS flag.
If it is a GC bug, you may be able to avoid it by using a particular heap size or by using a `-F2s' runtime flag. (But don't forget to report the bug!!!)
This part of the guide is to help people upgrading from a previous version of GHC. Right now, it is mostly to help people switching from GHC 0.29 (a Haskell 1.2 compiler, mostly) to GHC 2.04 (a Haskell 1.4 compiler).
If you need to maintain Haskell code that will work for multiple versions of GHC, you can use the `-cpp' flag and the `__GLASGOW_HASKELL__' pre-processor variable.
For example, in GHC 0.29, `__GLASGOW_HASKELL__' will be 29; for 2.04,
it will be 204. Thus, you can write:
#if __HASKELL1__ <= 2 main = appendChan stdout "Hello, world!\n" exit done -- 1.2 #else # if __GLASGOW_HASKELL__ >= 200 import IO main = putStr "Hello, world!" -- real 1.3 # else main = putStr "Hello, world!\n" -- pseudo-1.3 in 0.2x # endif #endif
A big new thing in Haskell 1.3 is constructor classes. Humble old functions such as `map' now have an exciting new type:
map :: Functor f => (a->b) -> f a -> f b
These new overloadings, expecially where it's the type constructor that's overloaded (as in `map') can give rise to some puzzling error messages. For example:
---------------------------------------------------------------------- lookupColor :: String -> [(String, (a, b, c))] -> (a, b, c) lookupColor colorName colorTable = head [(r,g,b) | (c,(r,g,b)) <- colorTable, c == map toLower colorName] ----------------------------------------------------------------------
With the type signature this is fine, but if you omit the type signature you'll get:
"Color.hs", line 49: No instance for: Prelude.Eq (a{-a18d-} Prelude.Char) "Color.hs", line 49: at a use of an overloaded identifier: `Prelude.meth.Prelude.Eq.=='
`map' no longer says that `colorName' has to be a list; it could be any type of the form (t `Char'). Unfortunately, lookupColor has to take equality over these (t `Char') things, so it gets stuck trying to figure out how to resolve (`Eq' (t `Char')) when it knows nothing about t.
The solution to such messages is to add type signatures.
Old uses of `compose' (`(.)') can magically turn into qualified names; e.g., `LiteralInt.leStringToInt'; add spaces.
Leading-underscore names (a Glasgow extension) don't work anymore, even with `-fglasgow-exts'.
The `Prelude.lex' function doesn't grok Haskell comments any more (a good simplification, but a change nonetheless).
You used to be able to define non-binary functions in a pseudo-infix-y say; e.g., `(a `op` b) c = ...'. Illegal now.
New keyword: `do'. Any old variables named `do' will now cause syntax errors.
In most cases, it's really easy to convert from Haskell 1.2's I/O to the monadic I/O of Haskell 1.3.
"Main.hs", line 32: No instance for: Prelude.MonadZero IO "Main.hs", line 32: in a do statementThis probably means that you need to "twiddle" some patterns; e.g., I added the twiddle to the `getArgs'-related pattern here:
main = do ~[a1] <- getArgs let x = fst (head ((reads::ReadS Int) a1) putStr (show (result x))
GHC 0.29 supported an early DRAFT of the Haskell 1.3 monadic I/O facilities. Inevitably, what Really Made It into 1.3 is not quite what was in the draft.
What was called `handle' in the draft is now called `catch'.
The type of the function `fail' changed between draft and real-thing. Old: `fail x'; new: `fail (userError x)'. Also, what used to be `failWith x' is now just `fail x'.
The function `try' didn't make it into 1.3 I/O. GHC supplies it (at least for now) as `GHCio.tryIO'.
All the system modules named `LibSomething' dropped the `Lib'. So: `LibSystem' is now just `System'.
In 0.29, you could mix-n-match `IO' with `PrimIO', simply because the implementation happend to allow it. Not any more.
The `IOError' type is now abstract; you cannot see it's constructors. 1.3 provides functions to query errors.
As with any previous Prelude/standard-modules changes, if you have top-level functions that name-clash with imported entities, you'll get compiler errors. So, for example, if your code defines a function called `seq' (entirely cool in Haskell 1.2), you will now get a compiler error because there is now a Prelude entity called `seq'. (You may, of course, `import Prelude hiding (seq)', if you wish).
Names that frequently clash with new Prelude names: `fail', `lookup', `seq'.
Add `import Ratio' if you use `Rationals' at all. Ditto: `import Complex' if you use complex numbers. Ditto: `import Array' if you use arrays.
As suggested above, any `LibXXX' system modules are now just `XXX'.
Also: note that Arrays now use ordinary pairs, rather than a separate `Assoc' type. In some modules, we've found it easier to do:
infix 1 =: (=:) a b = (a,b)
and globally replace `:=' with `=:'. Works fine for expressions; useless for patterns, however.
For `minInt'/`maxInt' and `minChar'/`maxChar', use the `Bounded' class methods, `minBound' and `maxBound'.
Replace class `Text' with `Show'; on rare occasions, you may need to do something for `Read', too.
The functions `ord' and `chr' have been replaced by the class methods `fromEnum' and `toEnum', respectively. The changes, however, can lead to ambiguous overloading.
The functions `even' and `odd' used to be methods of class `Integral'. They are now ordinary, overloaded functions.
The `print' function now appends a newline to its output. This is good, but different.
`readDec' no longer exists; use `(reads::ReadS Int)', or similar.
If you relied on `take', `drop', `splitAt', etc., being overloaded, you will need to switch to `genericTake', `genericDrop', etc., (imported from `List').
GHC 2.04 is fussier than 0.29 about junk in import lists. This is a feature.
`Foo..' (in export lists) must be changed to `module Foo'.
Type synonyms may be imported/exported with or without `(..)' -- it was required in Haskell 1.2--but you get a warning if you do it with.
Leading-underscore names are gone. Simon hated them.
To get access to GHC innards, you will need to import system modules with names of the form `GHCxxx'. We plan to restrict access to such interfaces in the future; and, of course, we reserve the right to make horrible changes to `GHC*' modules....
You can't dig around inside the `ST'/`IO' monads quite so freely.
If you want to provide your own `mainPrimIO' routine, it must be in a module `GHCmain', not `Main'.
The old `PreludePrimIO' interface is DEAD.
The even-older `PreludeGlaIO' interface is DEADER.
`returnPrimIO', `thenPrimIO', and `seqPrimIO' are deprecated. You were warned.
`foldrPrimIO' has died.
`_FILE', `fclose', `fdopen', `fflush', `fopen', `fread', `freopen', and `fwrite' are dead.
`appendChanPrimIO', `appendFilePrimIO', `getArgsPrimIO', and `readChanPrimIO' are dead (as previously warned).
The `LibPosix' stuff didn't make it into 1.3 I/O, so it has become a "system library" (`-syslib posix'). Other than dropping the `Lib*' prefix, everything should be the same as in 0.29.
This section lists Glasgow Haskell infelicities in its implementation of Haskell 1.4. See also the "when things go wrong" section (section 12 What to do when something goes wrong) for information about crashes, space leaks, and other undesirable phenomena.
GHC 2.02 does not have a "Haskell 1.2 compatibility mode." If enough people yelled loudly and long enough, it could conceivably happen...
The limitations here are listed in Haskell-Report order (roughly).
main = print (array (1,1) [ 1:=2, 1:=3 ])
This section describes how GHC supports separate compilation.
When GHC compiles a source module `A', it generates an object `A.o', and a companion interface file `A.hi'. The interface file contains information needed by the compiler when it compiles any module `B' that imports `A', whether directly or indirectly. When compiling `B', GHC will read `A.hi' to find the details that it needs to know about things defined in `A'.
Furthermore, when compiling module `C' which imports `B', GHC may decide that it needs to know something about `A' -- for example, `B' might export a function that involves a type defined in `A'. In this case, GHC will go and read `A.hi' even though `C' does not explicitly import `A' at all.
The interface file may contain all sorts of things that aren't explicitly exported from `A' by the programmer. For example, even though a data type is exported abstractly, `A.hi' will contain the full data type definition. For small function definitions, `A.hi' will contain the complete definition of the function. For bigger functions, `A.hi' will contain strictness information about the function. And so on. GHC puts much more information into `.hi' files when you use `-O'. Without `-O' it puts in just the minimum; with `-O' it lobs in a whole pile of stuff.
`A.hi' should really be thought of as a compiler-readable version of `A.o'. If you use a `.hi' file that wasn't generated by the same compilation run that generates the `.o' file the compiler may assume all sorts of incorrect things about `A', resulting in core dumps and other unpleasant happenings.
In the olden days, GHC compared the newly-generated `.hi' file with the previous version; if they were identical, it left the old one alone and didn't change its modification date. In consequence, importers of a module with an unchanged output `.hi' file were not recompiled.
This doesn't work any more. In our earlier example, module `C' does not import module `A' directly, yet changes to `A.hi' should force a recompilation of `C'. And some changes to `A' (changing the definition of a function that appears in an inlining of a function exported by `B', say) may conceivably not change `B.hi' one jot. So now
GHC keeps a version number on each interface file, and on each type signature within the interface file. It also keeps in every interface file a list of the version numbers of everything it used when it last compiled the file. If the source file's modification date is earlier than the `.o' file's date (i.e. the source hasn't changed since the file was last compiled), and you give GHC the `-recomp' flag, then GHC will be clever. It compares the version numbers on the things it needs this time with the version numbers on the things it needed last time (gleaned from the interface file of the module being compiled); if they are all the same it stops compiling rather early in the process saying "Recompilation not required". What a beautiful sight!
It's still an experimental feature (that's why `-recomp' is off by default), so tell us if you think it doesn't work.
Patrick Sansom has a workshop paper about how all this is done. Ask him (email: `sansom') if you want a copy.
It is reasonably straightforward to set up a `Makefile' to use with GHC, assuming you name your source files the same as your modules. Thus:
HC = ghc HC_OPTS = -cpp $(EXTRA_HC_OPTS) SRCS = Main.lhs Foo.lhs Bar.lhs OBJS = Main.o Foo.o Bar.o .SUFFIXES : .o .hi .lhs .hc .s cool_pgm : $(OBJS) $(RM) $@ $(HC) -o $@ $(HC_OPTS) $(OBJS) # Standard suffix rules .o.hi: @: .lhs.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) .hs.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) # Optional .hc.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) # Optional .s.o: $(RM) $@ $(HC) -c $< $(HC_OPTS) # Inter-module dependencies Foo.o Foo.hc Foo.s : Baz.hi # Foo imports Baz Main.o Main.hc Main.s : Foo.hi Baz.hi # Main imports Foo and Baz
(Sophisticated `make' variants may achieve some of the above more elegantly. Notably, `gmake''s pattern rules let you write the more comprehensible:
%.o : %.lhs $(RM) $@ $(HC) -c $< $(HC_OPTS)
What we've shown should work with any `make'.)
Note the cheesy `.o.hi' rule: It records the dependency of the interface (`.hi') file on the source. The rule says a `.hi' file can be made from a `.o' file by doing... nothing. Which is true.
Note the inter-module dependencies at the end of the Makefile, which take the form
Foo.o Foo.hc Foo.s : Baz.hi # Foo imports Baz
They tell `make' that if any of `Foo.o', `Foo.hc' or `Foo.s' have an earlier modification date than `Baz.hi', then the out-of-date file must be brought up to date. To bring it up to date, `make' looks for a rule to do so; one of the preceding suffix rules does the job nicely.
Putting inter-dependencies of the form `Foo.o : Bar.hi' into your `Makefile' by hand is rather error-prone. Don't worry -- never fear, `mkdependHS' is here! (and is distributed as part of GHC) Add the following to your `Makefile':
depend : mkdependHS -- $(HC_OPTS) -- $(SRCS)
Now, before you start compiling, and any time you change the `imports' in your program, do `make depend' before you do `make cool_pgm'. `mkdependHS' will append the needed dependencies to your `Makefile'. `mkdependHS' is fully describe in Section 16.1 Makefile dependencies in Haskell: using `mkdependHS'.
A few caveats about this simple scheme: (a) You may need to compile some modules explicitly to create their interfaces in the first place (e.g., `make Bar.o' to create `Bar.hi'). (b) You may have to type `make' more than once for the dependencies to have full effect. However, a `make' run that does nothing does mean "everything's up-to-date." (c) This scheme will work with mutually-recursive modules but, again, it may take multiple iterations to "settle."
This section describes other program(s) which we distribute, that help with the Great Haskell Programming Task.
You run `mkdependHS' like this:
mkdependHS [mkdependHS options] [-- GHC options --] srcfile1 [srcfile2 ...]
or
ghc -M [mkdependHS options(prefix with -optdep)] [ GHC options ] srcfile1 [srcfile2 ...]
To see `mkdependHS''s command-line flags, give it a duff flag, e.g., `mkdependHS -help'.
In general, if module `A' contains the line
import B ...blah...
then `mkdependHS' will generate a dependency line of the form:
A.o : B.hi
If module `A' contains the line
import {-# SOURCE #-} B ...blah...
then `mkdependHS' will generate a dependency line of the form:
A.o : B.hi-boot
(See Section 15.1 Interface files for details of interface files.) If `A' imports multiple modules, then there will be multiple lines with `A.o' as the target.
By default, `mkdependHS' generates all the dependencies, and then concatenates them onto the end of `makefile' (or `Makefile' if `makefile' doesn't exist) bracketed by the lines "`# DO NOT DELETE: Beginning of Haskell dependencies'" and "`# DO NOT DELETE: End of Haskell dependencies'". If these lines already exist in the `makefile', `mkdependHS' deletes the old dependencies first.
`mkdependHS' takes GHC options between `--' brackets. It understands the following ones. Any options between `--' brackets that it doesn't understand are simply ignored; this way you can feed your Makefile's standard GHC options to `mkdependHS' un-filtered.
Here are the `mkdependHS'-specific options (not between `--''s):
`Tags' is a facility for indexing the definitions of programming-language things in a multi-file program, and then using that index to jump around among these definitions.
Rather than scratch your head, saying "Now where did we define `foo'?", you just do (in Emacs) `M-. foo RET', and You're There! Some people go wild over this stuff...
GHC comes with a program `hstags', which build Emacs-able TAGS
files. The invocation syntax is:
hstags [GHC-options] file [files...]
The best thing is just to feed it your GHC command-line flags. A good Makefile entry might be:
tags: $(RM) TAGS hstags $(GHC_FLAGS) *.lhs
The only flags of its own are: `-v' to be verbose; `-a' to **APPEND** to the TAGS file, rather than write to it.
Shortcomings: (1) Instance declarations don't get into the TAGS file (but the definitions inside them do); as instances aren't named, this is probably just as well. (2) Data-constructor definitions don't get in. Go for the corresponding type constructor instead.
(Actually, GHC also comes with `etags' [for C], and `perltags' [for You Know What]. And -- I cannot tell a lie -- there is Denis Howe's `fptags' [for Haskell, etc.] in the `ghc/CONTRIB' section...)
Andy Gill and Simon Marlow have written a parser-generator for Haskell, called `happy'. `Happy' is to Haskell what `Yacc' is to C.
You can get `happy' by FTP from `ftp.dcs.gla.ac.uk' in `pub/haskell/happy', the file `happy-0.8.tar.gz'.
`Happy' is at its shining best when compiled by GHC.
Andrew Preece has written `pphs', a utility to pretty-print Haskell code in LaTeX documents. Keywords in bolds, variables in italics -- that sort of thing. It is good at lining up program clauses and equals signs, things that are very tiresome to do by hand.
The code is distributed with GHC in `ghc/CONTRIB/pphs'.
(ToDo: document properly.)
It is possible to compile Glasgow Haskell programs so that they will count lots and lots of interesting things, e.g., number of updates, number of data constructors entered, etc., etc. We call this "ticky-ticky" profiling, because that's the sound a Sun4 makes when it is running up all those counters (slowly).
Ticky-ticky profiling is mainly intended for implementors; it is quite separate from the main "cost-centre" profiling system, intended for all users everywhere.
To be able to use ticky-ticky profiling, you will need to have built appropriate libraries and things when you made the system. See "Customising what libraries to build," in the installation guide.
To get your compiled program to spit out the ticky-ticky numbers, use
a `-r' RTS option.
This guide assumes quite a bit of knowledge about UNIX compilers and their conventional use. This section has a little extra information for those who are new at this racket.
The Glorious Haskell Compilation System, as with most UNIX (batch) compilation systems, has several interacting parts:
You invoke the Glasgow Haskell compilation system through the
driver program `ghc'. For example, if you had typed a
literate "Hello, world!" program into `hello.lhs', and you then
invoked:
ghc hello.lhs
the following would happen:
You have considerable control over the compilation process. You feed command-line arguments (call them "options," for short) to the driver, `ghc'; the "types" of the input files (as encoded in their names' suffixes) also matter.
Here's hoping this is enough background so that you can read the rest of this guide!
This document was generated on 3 December 1997 using the texi2html translator version 1.51.