[project @ 2000-10-31 17:30:16 by simonpj]
[ghc-hetmet.git] / ghc / compiler / main / CmdLineOpts.lhs
1 %
2 % (c) The University of Glasgow, 1996-2000
3 %
4 \section[CmdLineOpts]{Things to do with command-line options}
5
6 \begin{code}
7
8 module CmdLineOpts (
9         CoreToDo(..),
10         SimplifierSwitch(..), isAmongSimpl,
11         StgToDo(..),
12         SwitchResult(..),
13         HscLang(..),
14         DynFlag(..),    -- needed non-abstractly by DriverFlags
15         DynFlags(..),
16
17         v_Static_hsc_opts,
18
19         intSwitchSet,
20         switchIsOn,
21         isStaticHscFlag,
22
23         opt_PprStyle_NoPrags,
24         opt_PprUserLength,
25         opt_PprStyle_Debug,
26
27         dopt,
28
29         -- other dynamic flags
30         dopt_CoreToDo,
31         dopt_StgToDo,
32         dopt_HscLang,
33         dopt_OutName,
34
35         -- profiling opts
36         opt_AutoSccsOnAllToplevs,
37         opt_AutoSccsOnExportedToplevs,
38         opt_AutoSccsOnIndividualCafs,
39         opt_AutoSccsOnDicts,
40         opt_SccProfilingOn,
41         opt_DoTickyProfiling,
42
43         -- language opts
44         opt_AllStrict,
45         opt_DictsStrict,
46         opt_MaxContextReductionDepth,
47         opt_IrrefutableTuples,
48         opt_NumbersStrict,
49         opt_Parallel,
50         opt_SMP,
51
52         -- optimisation opts
53         opt_DoSemiTagging,
54         opt_FoldrBuildOn,
55         opt_LiberateCaseThreshold,
56         opt_StgDoLetNoEscapes,
57         opt_UnfoldCasms,
58         opt_UsageSPOn,
59         opt_UnboxStrictFields,
60         opt_SimplNoPreInlining,
61         opt_SimplDoEtaReduction,
62         opt_SimplDoLambdaEtaExpansion,
63         opt_SimplCaseOfCase,
64         opt_SimplCaseMerge,
65         opt_SimplPedanticBottoms,
66         opt_SimplExcessPrecision,
67
68         -- Unfolding control
69         opt_UF_HiFileThreshold,
70         opt_UF_CreationThreshold,
71         opt_UF_UseThreshold,
72         opt_UF_FunAppDiscount,
73         opt_UF_KeenessFactor,
74         opt_UF_UpdateInPlace,
75         opt_UF_CheapOp,
76         opt_UF_DearOp,
77
78         -- misc opts
79         opt_InPackage,
80         opt_EmitCExternDecls,
81         opt_EnsureSplittableC,
82         opt_GranMacros,
83         opt_HiVersion,
84         opt_HistorySize,
85         opt_IgnoreAsserts,
86         opt_IgnoreIfacePragmas,
87         opt_NoHiCheck,
88         opt_OmitBlackHoling,
89         opt_OmitInterfacePragmas,
90         opt_NoPruneTyDecls,
91         opt_NoPruneDecls,
92         opt_Static,
93         opt_Unregisterised,
94         opt_Verbose
95     ) where
96
97 #include "HsVersions.h"
98
99 import Array    ( array, (//) )
100 import GlaExts
101 import IOExts   ( IORef, readIORef )
102 import Constants        -- Default values for some flags
103 import Util
104 import FastTypes
105
106 import Maybes           ( firstJust )
107 import Panic            ( panic )
108
109 #if __GLASGOW_HASKELL__ < 301
110 import ArrBase  ( Array(..) )
111 #else
112 import PrelArr  ( Array(..) )
113 #endif
114 \end{code}
115
116 %************************************************************************
117 %*                                                                      *
118 \subsection{Command-line options}
119 %*                                                                      *
120 %************************************************************************
121
122 The hsc command-line options are split into two categories:
123
124   - static flags
125   - dynamic flags
126
127 Static flags are represented by top-level values of type Bool or Int,
128 for example.  They therefore have the same value throughout the
129 invocation of hsc.
130
131 Dynamic flags are represented by an abstract type, DynFlags, which is
132 passed into hsc by the compilation manager for every compilation.
133 Dynamic flags are those that change on a per-compilation basis,
134 perhaps because they may be present in the OPTIONS pragma at the top
135 of a module.
136
137 Other flag-related blurb:
138
139 A list of {\em ToDo}s is things to be done in a particular part of
140 processing.  A (fictitious) example for the Core-to-Core simplifier
141 might be: run the simplifier, then run the strictness analyser, then
142 run the simplifier again (three ``todos'').
143
144 There are three ``to-do processing centers'' at the moment.  In the
145 main loop (\tr{main/Main.lhs}), in the Core-to-Core processing loop
146 (\tr{simplCore/SimplCore.lhs), and in the STG-to-STG processing loop
147 (\tr{simplStg/SimplStg.lhs}).
148
149 %************************************************************************
150 %*                                                                      *
151 \subsection{Datatypes associated with command-line options}
152 %*                                                                      *
153 %************************************************************************
154
155 \begin{code}
156 data SwitchResult
157   = SwBool      Bool            -- on/off
158   | SwString    FAST_STRING     -- nothing or a String
159   | SwInt       Int             -- nothing or an Int
160 \end{code}
161
162 \begin{code}
163 data CoreToDo           -- These are diff core-to-core passes,
164                         -- which may be invoked in any order,
165                         -- as many times as you like.
166
167   = CoreDoSimplify      -- The core-to-core simplifier.
168         (SimplifierSwitch -> SwitchResult)
169                         -- Each run of the simplifier can take a different
170                         -- set of simplifier-specific flags.
171   | CoreDoFloatInwards
172   | CoreDoFloatOutwards Bool    -- True <=> float lambdas to top level
173   | CoreLiberateCase
174   | CoreDoPrintCore
175   | CoreDoStaticArgs
176   | CoreDoStrictness
177   | CoreDoWorkerWrapper
178   | CoreDoSpecialising
179   | CoreDoUSPInf
180   | CoreDoCPResult
181   | CoreDoGlomBinds
182   | CoreCSE
183
184   | CoreDoNothing        -- useful when building up lists of these things
185 \end{code}
186
187 \begin{code}
188 data StgToDo
189   = StgDoStaticArgs
190   | StgDoLambdaLift
191   | StgDoMassageForProfiling  -- should be (next to) last
192   -- There's also setStgVarInfo, but its absolute "lastness"
193   -- is so critical that it is hardwired in (no flag).
194   | D_stg_stats
195 \end{code}
196
197 \begin{code}
198 data SimplifierSwitch
199   = MaxSimplifierIterations Int
200   | SimplInlinePhase Int
201   | DontApplyRules
202   | NoCaseOfCase
203   | SimplLetToCase
204 \end{code}
205
206 %************************************************************************
207 %*                                                                      *
208 \subsection{Dynamic command-line options}
209 %*                                                                      *
210 %************************************************************************
211
212 \begin{code}
213 data DynFlag
214
215    -- debugging flags
216    = Opt_D_dump_all
217    | Opt_D_dump_most
218    | Opt_D_dump_absC
219    | Opt_D_dump_asm
220    | Opt_D_dump_cpranal
221    | Opt_D_dump_deriv
222    | Opt_D_dump_ds
223    | Opt_D_dump_flatC
224    | Opt_D_dump_foreign
225    | Opt_D_dump_inlinings
226    | Opt_D_dump_occur_anal
227    | Opt_D_dump_parsed
228    | Opt_D_dump_realC
229    | Opt_D_dump_rn
230    | Opt_D_dump_simpl
231    | Opt_D_dump_simpl_iterations
232    | Opt_D_dump_spec
233    | Opt_D_dump_stg
234    | Opt_D_dump_stranal
235    | Opt_D_dump_tc
236    | Opt_D_dump_types
237    | Opt_D_dump_rules
238    | Opt_D_dump_usagesp
239    | Opt_D_dump_cse
240    | Opt_D_dump_worker_wrapper
241    | Opt_D_show_passes
242    | Opt_D_dump_rn_trace
243    | Opt_D_dump_rn_stats
244    | Opt_D_dump_stix
245    | Opt_D_dump_simpl_stats
246    | Opt_D_source_stats
247    | Opt_D_verbose_core2core
248    | Opt_D_verbose_stg2stg
249    | Opt_D_dump_hi_diffs
250    | Opt_D_dump_minimal_imports
251    | Opt_DoCoreLinting
252    | Opt_DoStgLinting
253    | Opt_DoUSPLinting
254
255    | Opt_WarnDuplicateExports
256    | Opt_WarnHiShadows
257    | Opt_WarnIncompletePatterns
258    | Opt_WarnMissingFields
259    | Opt_WarnMissingMethods
260    | Opt_WarnMissingSigs
261    | Opt_WarnNameShadowing
262    | Opt_WarnOverlappingPatterns
263    | Opt_WarnSimplePatterns
264    | Opt_WarnTypeDefaults
265    | Opt_WarnUnusedBinds
266    | Opt_WarnUnusedImports
267    | Opt_WarnUnusedMatches
268    | Opt_WarnDeprecations
269
270    -- language opts
271    | Opt_AllowOverlappingInstances
272    | Opt_AllowUndecidableInstances
273    | Opt_GlasgowExts
274    | Opt_Generics
275    | Opt_NoImplicitPrelude 
276
277    -- misc
278    | Opt_ReportCompile
279    deriving (Eq)
280
281 data DynFlags = DynFlags {
282   coreToDo   :: [CoreToDo],
283   stgToDo    :: [StgToDo],
284   hscLang    :: HscLang,
285   hscOutName :: String,  -- name of the file in which to place output
286   flags      :: [DynFlag]
287  }
288
289 dopt :: DynFlag -> DynFlags -> Bool
290 dopt f dflags  = f `elem` (flags dflags)
291
292 dopt_CoreToDo :: DynFlags -> [CoreToDo]
293 dopt_CoreToDo = coreToDo
294
295 dopt_StgToDo :: DynFlags -> [StgToDo]
296 dopt_StgToDo = stgToDo
297
298 dopt_OutName :: DynFlags -> String
299 dopt_OutName = hscOutName
300
301 data HscLang
302   = HscC
303   | HscAsm
304   | HscJava
305   | HscInterpreted
306     deriving Eq
307
308 dopt_HscLang :: DynFlags -> HscLang
309 dopt_HscLang = hscLang
310 \end{code}
311
312 %************************************************************************
313 %*                                                                      *
314 \subsection{Classifying command-line options}
315 %*                                                                      *
316 %************************************************************************
317
318 \begin{code}
319 -- v_Statis_hsc_opts is here to avoid a circular dependency with
320 -- main/DriverState.
321 GLOBAL_VAR(v_Static_hsc_opts, [], [String])
322
323 lookUp           :: FAST_STRING -> Bool
324 lookup_int       :: String -> Maybe Int
325 lookup_def_int   :: String -> Int -> Int
326 lookup_def_float :: String -> Float -> Float
327 lookup_str       :: String -> Maybe String
328
329 unpacked_static_opts = unsafePerformIO (readIORef v_Static_hsc_opts)
330 packed_static_opts   = map _PK_ unpacked_static_opts
331
332 lookUp     sw = sw `elem` packed_static_opts
333         
334 lookup_str sw = firstJust (map (startsWith sw) unpacked_static_opts)
335
336 lookup_int sw = case (lookup_str sw) of
337                   Nothing -> Nothing
338                   Just xx -> Just (read xx)
339
340 lookup_def_int sw def = case (lookup_str sw) of
341                             Nothing -> def              -- Use default
342                             Just xx -> read xx
343
344 lookup_def_char sw def = case (lookup_str sw) of
345                             Just (xx:_) -> xx
346                             _           -> def          -- Use default
347
348 lookup_def_float sw def = case (lookup_str sw) of
349                             Nothing -> def              -- Use default
350                             Just xx -> read xx
351
352
353 {-
354  Putting the compiler options into temporary at-files
355  may turn out to be necessary later on if we turn hsc into
356  a pure Win32 application where I think there's a command-line
357  length limit of 255. unpacked_opts understands the @ option.
358
359 unpacked_opts :: [String]
360 unpacked_opts =
361   concat $
362   map (expandAts) $
363   map _UNPK_ argv  -- NOT ARGV any more: v_Static_hsc_opts
364   where
365    expandAts ('@':fname) = words (unsafePerformIO (readFile fname))
366    expandAts l = [l]
367 -}
368 \end{code}
369
370 %************************************************************************
371 %*                                                                      *
372 \subsection{Static options}
373 %*                                                                      *
374 %************************************************************************
375
376 \begin{code}
377 -- debugging opts
378 opt_PprStyle_NoPrags            = lookUp  SLIT("-dppr-noprags")
379 opt_PprStyle_Debug              = lookUp  SLIT("-dppr-debug")
380 opt_PprUserLength               = lookup_def_int "-dppr-user-length" 5 --ToDo: give this a name
381
382 -- profiling opts
383 opt_AutoSccsOnAllToplevs        = lookUp  SLIT("-fauto-sccs-on-all-toplevs")
384 opt_AutoSccsOnExportedToplevs   = lookUp  SLIT("-fauto-sccs-on-exported-toplevs")
385 opt_AutoSccsOnIndividualCafs    = lookUp  SLIT("-fauto-sccs-on-individual-cafs")
386 opt_AutoSccsOnDicts             = lookUp  SLIT("-fauto-sccs-on-dicts")
387 opt_SccProfilingOn              = lookUp  SLIT("-fscc-profiling")
388 opt_DoTickyProfiling            = lookUp  SLIT("-fticky-ticky")
389
390 -- language opts
391 opt_AllStrict                   = lookUp  SLIT("-fall-strict")
392 opt_DictsStrict                 = lookUp  SLIT("-fdicts-strict")
393 opt_IrrefutableTuples           = lookUp  SLIT("-firrefutable-tuples")
394 opt_MaxContextReductionDepth    = lookup_def_int "-fcontext-stack" mAX_CONTEXT_REDUCTION_DEPTH
395 opt_NumbersStrict               = lookUp  SLIT("-fnumbers-strict")
396 opt_Parallel                    = lookUp  SLIT("-fparallel")
397 opt_SMP                         = lookUp  SLIT("-fsmp")
398
399 -- optimisation opts
400 opt_DoSemiTagging               = lookUp  SLIT("-fsemi-tagging")
401 opt_FoldrBuildOn                = lookUp  SLIT("-ffoldr-build-on")
402 opt_LiberateCaseThreshold       = lookup_def_int "-fliberate-case-threshold" (10::Int)
403 opt_StgDoLetNoEscapes           = lookUp  SLIT("-flet-no-escape")
404 opt_UnfoldCasms                 = lookUp SLIT("-funfold-casms-in-hi-file")
405 opt_UsageSPOn                   = lookUp  SLIT("-fusagesp-on")
406 opt_UnboxStrictFields           = lookUp  SLIT("-funbox-strict-fields")
407
408 {-
409    The optional '-inpackage=P' flag tells what package
410    we are compiling this module for.
411    The Prelude, for example is compiled with '-package prelude'
412 -}
413 opt_InPackage                   = case lookup_str "-inpackage=" of
414                                     Just p  -> _PK_ p
415                                     Nothing -> SLIT("Main")     -- The package name if none is specified
416
417 opt_EmitCExternDecls            = lookUp  SLIT("-femit-extern-decls")
418 opt_EnsureSplittableC           = lookUp  SLIT("-fglobalise-toplev-names")
419 opt_GranMacros                  = lookUp  SLIT("-fgransim")
420 opt_HiVersion                   = lookup_def_int "-fhi-version=" 0 -- what version we're compiling.
421 opt_HistorySize                 = lookup_def_int "-fhistory-size" 20
422 opt_IgnoreAsserts               = lookUp  SLIT("-fignore-asserts")
423 opt_IgnoreIfacePragmas          = lookUp  SLIT("-fignore-interface-pragmas")
424 opt_NoHiCheck                   = lookUp  SLIT("-fno-hi-version-check")
425 opt_OmitBlackHoling             = lookUp  SLIT("-dno-black-holing")
426 opt_OmitInterfacePragmas        = lookUp  SLIT("-fomit-interface-pragmas")
427
428 -- Simplifier switches
429 opt_SimplNoPreInlining          = lookUp SLIT("-fno-pre-inlining")
430         -- NoPreInlining is there just to see how bad things
431         -- get if you don't do it!
432 opt_SimplDoEtaReduction         = lookUp SLIT("-fdo-eta-reduction")
433 opt_SimplDoLambdaEtaExpansion   = lookUp SLIT("-fdo-lambda-eta-expansion")
434 opt_SimplCaseOfCase             = lookUp SLIT("-fcase-of-case")
435 opt_SimplCaseMerge              = lookUp SLIT("-fcase-merge")
436 opt_SimplPedanticBottoms        = lookUp SLIT("-fpedantic-bottoms")
437 opt_SimplExcessPrecision        = lookUp SLIT("-fexcess-precision")
438
439 -- Unfolding control
440 opt_UF_HiFileThreshold          = lookup_def_int "-funfolding-interface-threshold" (45::Int)
441 opt_UF_CreationThreshold        = lookup_def_int "-funfolding-creation-threshold"  (45::Int)
442 opt_UF_UseThreshold             = lookup_def_int "-funfolding-use-threshold"       (8::Int)     -- Discounts can be big
443 opt_UF_FunAppDiscount           = lookup_def_int "-funfolding-fun-discount"        (6::Int)     -- It's great to inline a fn
444 opt_UF_KeenessFactor            = lookup_def_float "-funfolding-keeness-factor"    (1.5::Float)
445 opt_UF_UpdateInPlace            = lookUp  SLIT("-funfolding-update-in-place")
446
447 opt_UF_CheapOp  = ( 1 :: Int)   -- Only one instruction; and the args are charged for
448 opt_UF_DearOp   = ( 4 :: Int)
449                         
450 opt_NoPruneDecls                = lookUp SLIT("-fno-prune-decls")
451 opt_NoPruneTyDecls              = lookUp SLIT("-fno-prune-tydecls")
452 opt_Static                      = lookUp SLIT("-static")
453 opt_Unregisterised              = lookUp SLIT("-funregisterised")
454 opt_Verbose                     = lookUp SLIT("-v")
455 \end{code}
456
457 %************************************************************************
458 %*                                                                      *
459 \subsection{List of static hsc flags}
460 %*                                                                      *
461 %************************************************************************
462
463 \begin{code}
464 isStaticHscFlag f =
465   f `elem` [
466         "fauto-sccs-on-all-toplevs",
467         "fauto-sccs-on-exported-toplevs",
468         "fauto-sccs-on-individual-cafs",
469         "fauto-sccs-on-dicts",
470         "fscc-profiling",
471         "fticky-ticky",
472         "fall-strict",
473         "fdicts-strict",
474         "firrefutable-tuples",
475         "fnumbers-strict",
476         "fparallel",
477         "fsmp",
478         "fsemi-tagging",
479         "ffoldr-build-on",
480         "flet-no-escape",
481         "funfold-casms-in-hi-file",
482         "fusagesp-on",
483         "funbox-strict-fields",
484         "femit-extern-decls",
485         "fglobalise-toplev-names",
486         "fgransim",
487         "fignore-asserts",
488         "fignore-interface-pragmas",
489         "fno-hi-version-check",
490         "fno-implicit-prelude",
491         "dno-black-holing",
492         "fomit-interface-pragmas",
493         "fno-pre-inlining",
494         "fdo-eta-reduction",
495         "fdo-lambda-eta-expansion",
496         "fcase-of-case",
497         "fcase-merge",
498         "fpedantic-bottoms",
499         "fexcess-precision",
500         "funfolding-update-in-place",
501         "freport-compile",
502         "fno-prune-decls",
503         "fno-prune-tydecls",
504         "static",
505         "funregisterised",
506         "v" ]
507   || any (flip prefixMatch f) [
508         "fcontext-stack",
509         "fliberate-case-threshold",
510         "fhi-version=",
511         "fhistory-size",
512         "funfolding-interface-threshold",
513         "funfolding-creation-threshold",
514         "funfolding-use-threshold",
515         "funfolding-fun-discount",
516         "funfolding-keeness-factor"
517      ]
518 \end{code}
519
520 %************************************************************************
521 %*                                                                      *
522 \subsection{Switch ordering}
523 %*                                                                      *
524 %************************************************************************
525
526 These things behave just like enumeration types.
527
528 \begin{code}
529 instance Eq SimplifierSwitch where
530     a == b = tagOf_SimplSwitch a ==# tagOf_SimplSwitch b
531
532 instance Ord SimplifierSwitch where
533     a <  b  = tagOf_SimplSwitch a <# tagOf_SimplSwitch b
534     a <= b  = tagOf_SimplSwitch a <=# tagOf_SimplSwitch b
535
536
537 tagOf_SimplSwitch (SimplInlinePhase _)          = _ILIT(1)
538 tagOf_SimplSwitch (MaxSimplifierIterations _)   = _ILIT(2)
539 tagOf_SimplSwitch DontApplyRules                = _ILIT(3)
540 tagOf_SimplSwitch SimplLetToCase                = _ILIT(4)
541 tagOf_SimplSwitch NoCaseOfCase                  = _ILIT(5)
542
543 -- If you add anything here, be sure to change lAST_SIMPL_SWITCH_TAG, too!
544
545 lAST_SIMPL_SWITCH_TAG = 5
546 \end{code}
547
548 %************************************************************************
549 %*                                                                      *
550 \subsection{Switch lookup}
551 %*                                                                      *
552 %************************************************************************
553
554 \begin{code}
555 isAmongSimpl :: [SimplifierSwitch] -> SimplifierSwitch -> SwitchResult
556 isAmongSimpl on_switches                -- Switches mentioned later occur *earlier*
557                                         -- in the list; defaults right at the end.
558   = let
559         tidied_on_switches = foldl rm_dups [] on_switches
560                 -- The fold*l* ensures that we keep the latest switches;
561                 -- ie the ones that occur earliest in the list.
562
563         sw_tbl :: Array Int SwitchResult
564         sw_tbl = (array (0, lAST_SIMPL_SWITCH_TAG) -- bounds...
565                         all_undefined)
566                  // defined_elems
567
568         all_undefined = [ (i, SwBool False) | i <- [0 .. lAST_SIMPL_SWITCH_TAG ] ]
569
570         defined_elems = map mk_assoc_elem tidied_on_switches
571     in
572     -- (avoid some unboxing, bounds checking, and other horrible things:)
573 #if __GLASGOW_HASKELL__ < 405
574     case sw_tbl of { Array bounds_who_needs_'em stuff ->
575 #else
576     case sw_tbl of { Array _ _ stuff ->
577 #endif
578     \ switch ->
579         case (indexArray# stuff (tagOf_SimplSwitch switch)) of
580 #if __GLASGOW_HASKELL__ < 400
581           Lift v -> v
582 #elif __GLASGOW_HASKELL__ < 403
583           (# _, v #) -> v
584 #else
585           (# v #) -> v
586 #endif
587     }
588   where
589     mk_assoc_elem k@(MaxSimplifierIterations lvl)
590         = (iBox (tagOf_SimplSwitch k), SwInt lvl)
591     mk_assoc_elem k@(SimplInlinePhase n)
592         = (iBox (tagOf_SimplSwitch k), SwInt n)
593     mk_assoc_elem k
594         = (iBox (tagOf_SimplSwitch k), SwBool True) -- I'm here, Mom!
595
596     -- cannot have duplicates if we are going to use the array thing
597     rm_dups switches_so_far switch
598       = if switch `is_elem` switches_so_far
599         then switches_so_far
600         else switch : switches_so_far
601       where
602         sw `is_elem` []     = False
603         sw `is_elem` (s:ss) = (tagOf_SimplSwitch sw) ==# (tagOf_SimplSwitch s)
604                             || sw `is_elem` ss
605 \end{code}
606
607 Default settings for simplifier switches
608
609 \begin{code}
610 defaultSimplSwitches = [MaxSimplifierIterations 1]
611 \end{code}
612
613 %************************************************************************
614 %*                                                                      *
615 \subsection{Misc functions for command-line options}
616 %*                                                                      *
617 %************************************************************************
618
619
620 \begin{code}
621 switchIsOn :: (switch -> SwitchResult) -> switch -> Bool
622
623 switchIsOn lookup_fn switch
624   = case (lookup_fn switch) of
625       SwBool False -> False
626       _            -> True
627
628 intSwitchSet :: (switch -> SwitchResult)
629              -> (Int -> switch)
630              -> Maybe Int
631
632 intSwitchSet lookup_fn switch
633   = case (lookup_fn (switch (panic "intSwitchSet"))) of
634       SwInt int -> Just int
635       _         -> Nothing
636 \end{code}
637
638 \begin{code}
639 startsWith :: String -> String -> Maybe String
640 -- startsWith pfx (pfx++rest) = Just rest
641
642 startsWith []     str = Just str
643 startsWith (c:cs) (s:ss)
644   = if c /= s then Nothing else startsWith cs ss
645 startsWith  _     []  = Nothing
646
647 endsWith  :: String -> String -> Maybe String
648 endsWith cs ss
649   = case (startsWith (reverse cs) (reverse ss)) of
650       Nothing -> Nothing
651       Just rs -> Just (reverse rs)
652 \end{code}