2 % (c) The University of Glasgow, 1996-2000
4 \section[CmdLineOpts]{Things to do with command-line options}
9 CoreToDo(..), buildCoreToDo, StgToDo(..),
11 SimplifierMode(..), FloatOutSwitches(..),
14 DynFlag(..), -- needed non-abstractly by DriverFlags
21 -- Manipulating DynFlags
22 defaultDynFlags, -- DynFlags
23 dopt, -- DynFlag -> DynFlags -> Bool
24 dopt_set, dopt_unset, -- DynFlags -> DynFlag -> DynFlags
25 dopt_CoreToDo, -- DynFlags -> [CoreToDo]
26 dopt_StgToDo, -- DynFlags -> [StgToDo]
27 dopt_HscLang, -- DynFlags -> HscLang
28 dopt_OutName, -- DynFlags -> String
29 getOpts, -- (DynFlags -> [a]) -> IO [a]
34 -- Manipulating the DynFlags state
35 getDynFlags, -- IO DynFlags
36 setDynFlags, -- DynFlags -> IO ()
37 updDynFlags, -- (DynFlags -> DynFlags) -> IO ()
38 dynFlag, -- (DynFlags -> a) -> IO a
39 setDynFlag, unSetDynFlag, -- DynFlag -> IO ()
40 saveDynFlags, -- IO ()
41 restoreDynFlags, -- IO DynFlags
43 -- sets of warning opts
47 -- Output style options
52 opt_AutoSccsOnAllToplevs,
53 opt_AutoSccsOnExportedToplevs,
54 opt_AutoSccsOnIndividualCafs,
60 opt_MaxContextReductionDepth,
61 opt_IrrefutableTuples,
70 opt_LiberateCaseThreshold,
73 opt_SimplNoPreInlining,
74 opt_SimplExcessPrecision,
78 opt_UF_CreationThreshold,
80 opt_UF_FunAppDiscount,
89 opt_EnsureSplittableC,
100 #include "HsVersions.h"
102 import Constants -- Default values for some flags
104 import FastString ( FastString, mkFastString )
106 import Maybes ( firstJust )
108 import Panic ( ghcError, GhcException(UsageError) )
110 import DATA_IOREF ( IORef, readIORef, writeIORef )
111 import UNSAFE_IO ( unsafePerformIO )
114 %************************************************************************
116 \subsection{Command-line options}
118 %************************************************************************
120 The hsc command-line options are split into two categories:
125 Static flags are represented by top-level values of type Bool or Int,
126 for example. They therefore have the same value throughout the
129 Dynamic flags are represented by an abstract type, DynFlags, which is
130 passed into hsc by the compilation manager for every compilation.
131 Dynamic flags are those that change on a per-compilation basis,
132 perhaps because they may be present in the OPTIONS pragma at the top
135 Other flag-related blurb:
137 A list of {\em ToDo}s is things to be done in a particular part of
138 processing. A (fictitious) example for the Core-to-Core simplifier
139 might be: run the simplifier, then run the strictness analyser, then
140 run the simplifier again (three ``todos'').
142 There are three ``to-do processing centers'' at the moment. In the
143 main loop (\tr{main/Main.lhs}), in the Core-to-Core processing loop
144 (\tr{simplCore/SimplCore.lhs), and in the STG-to-STG processing loop
145 (\tr{simplStg/SimplStg.lhs}).
147 %************************************************************************
149 \subsection{Datatypes associated with command-line options}
151 %************************************************************************
154 data CoreToDo -- These are diff core-to-core passes,
155 -- which may be invoked in any order,
156 -- as many times as you like.
158 = CoreDoSimplify -- The core-to-core simplifier.
161 -- Each run of the simplifier can take a different
162 -- set of simplifier-specific flags.
164 | CoreDoFloatOutwards FloatOutSwitches
169 | CoreDoWorkerWrapper
172 | CoreDoOldStrictness
175 | CoreDoRuleCheck Int{-CompilerPhase-} String -- Check for non-application of rules
176 -- matching this string
178 | CoreDoNothing -- useful when building up lists of these things
183 = StgDoMassageForProfiling -- should be (next to) last
184 -- There's also setStgVarInfo, but its absolute "lastness"
185 -- is so critical that it is hardwired in (no flag).
190 data SimplifierMode -- See comments in SimplMonad
194 data SimplifierSwitch
195 = MaxSimplifierIterations Int
198 data FloatOutSwitches
199 = FloatOutSw Bool -- True <=> float lambdas to top level
200 Bool -- True <=> float constants to top level,
201 -- even if they do not escape a lambda
204 %************************************************************************
206 \subsection{Dynamic command-line options}
208 %************************************************************************
221 | Opt_D_dump_inlinings
222 | Opt_D_dump_occur_anal
226 | Opt_D_dump_simpl_iterations
235 | Opt_D_dump_worker_wrapper
236 | Opt_D_dump_rn_trace
237 | Opt_D_dump_rn_stats
239 | Opt_D_dump_simpl_stats
240 | Opt_D_dump_tc_trace
241 | Opt_D_dump_if_trace
246 | Opt_D_verbose_core2core
247 | Opt_D_verbose_stg2stg
249 | Opt_D_dump_hi_diffs
250 | Opt_D_dump_minimal_imports
255 | Opt_WarnIsError -- -Werror; makes warnings fatal
256 | Opt_WarnDuplicateExports
258 | Opt_WarnIncompletePatterns
259 | Opt_WarnMissingFields
260 | Opt_WarnMissingMethods
261 | Opt_WarnMissingSigs
262 | Opt_WarnNameShadowing
263 | Opt_WarnOverlappingPatterns
264 | Opt_WarnSimplePatterns
265 | Opt_WarnTypeDefaults
266 | Opt_WarnUnusedBinds
267 | Opt_WarnUnusedImports
268 | Opt_WarnUnusedMatches
269 | Opt_WarnDeprecations
270 | Opt_WarnDodgyImports
273 | Opt_AllowOverlappingInstances
274 | Opt_AllowUndecidableInstances
275 | Opt_AllowIncoherentInstances
276 | Opt_NoMonomorphismRestriction
279 | Opt_PArr -- syntactic support for parallel arrays
280 | Opt_Arrows -- Arrow-notation syntax
284 | Opt_NoImplicitPrelude
290 | Opt_IgnoreInterfacePragmas
291 | Opt_OmitInterfacePragmas
292 | Opt_DoLambdaEtaExpansion
296 | Opt_UnboxStrictFields
300 data DynFlags = DynFlags {
301 coreToDo :: Maybe [CoreToDo], -- reserved for use with -Ofile
302 stgToDo :: [StgToDo],
304 hscOutName :: String, -- name of the output file
305 hscStubHOutName :: String, -- name of the .stub_h output file
306 hscStubCOutName :: String, -- name of the .stub_c output file
307 extCoreName :: String, -- name of the .core output file
308 verbosity :: Int, -- verbosity level
309 optLevel :: Int, -- optimisation level
310 maxSimplIterations :: Int, -- max simplifier iterations
311 ruleCheck :: Maybe String,
312 cppFlag :: Bool, -- preprocess with cpp?
313 ppFlag :: Bool, -- preprocess with a Haskell Pp?
314 stolen_x86_regs :: Int,
315 cmdlineHcIncludes :: [String], -- -#includes
317 -- options for particular phases
343 | cGhcWithNativeCodeGen == "YES" &&
344 (prefixMatch "i386" cTARGETPLATFORM ||
345 prefixMatch "sparc" cTARGETPLATFORM ||
346 prefixMatch "powerpc" cTARGETPLATFORM) = HscAsm
349 defaultDynFlags = DynFlags {
350 coreToDo = Nothing, stgToDo = [],
351 hscLang = defaultHscLang,
353 hscStubHOutName = "", hscStubCOutName = "",
357 maxSimplIterations = 4,
362 cmdlineHcIncludes = [],
375 -- Generating the helper-functions for
376 -- generics is now on by default
378 -- strictness is on by default, but this only
380 Opt_CSE, -- similarly for CSE.
381 Opt_FullLaziness, -- ...and for full laziness
383 Opt_DoLambdaEtaExpansion,
384 -- This one is important for a tiresome reason:
385 -- we want to make sure that the bindings for data
386 -- constructors are eta-expanded. This is probably
387 -- a good thing anyway, but it seems fragile.
389 -- and the default no-optimisation options:
390 Opt_IgnoreInterfacePragmas,
391 Opt_OmitInterfacePragmas
393 ] ++ standardWarnings
399 0 | print errors & warnings only
400 1 | minimal verbosity: print "compiling M ... done." for each module.
401 2 | equivalent to -dshow-passes
402 3 | equivalent to existing "ghc -v"
403 4 | "ghc -v -ddump-most"
404 5 | "ghc -v -ddump-all"
407 dopt :: DynFlag -> DynFlags -> Bool
408 dopt f dflags = f `elem` (flags dflags)
410 dopt_CoreToDo :: DynFlags -> Maybe [CoreToDo]
411 dopt_CoreToDo = coreToDo
413 dopt_StgToDo :: DynFlags -> [StgToDo]
414 dopt_StgToDo = stgToDo
416 dopt_OutName :: DynFlags -> String
417 dopt_OutName = hscOutName
419 dopt_HscLang :: DynFlags -> HscLang
420 dopt_HscLang = hscLang
422 dopt_set :: DynFlags -> DynFlag -> DynFlags
423 dopt_set dfs f = dfs{ flags = f : flags dfs }
425 dopt_unset :: DynFlags -> DynFlag -> DynFlags
426 dopt_unset dfs f = dfs{ flags = filter (/= f) (flags dfs) }
428 getOpts :: (DynFlags -> [a]) -> IO [a]
429 -- We add to the options from the front, so we need to reverse the list
430 getOpts opts = dynFlag opts >>= return . reverse
432 -- we can only switch between HscC, HscAsmm, and HscILX with dynamic flags
433 -- (-fvia-C, -fasm, -filx respectively).
434 setLang l = updDynFlags (\ dfs -> case hscLang dfs of
435 HscC -> dfs{ hscLang = l }
436 HscAsm -> dfs{ hscLang = l }
437 HscILX -> dfs{ hscLang = l }
441 verb <- dynFlag verbosity
442 if verb >= 3 then return "-v" else return ""
444 -----------------------------------------------------------------------------
445 -- Setting the optimisation level
447 setOptLevel :: Int -> IO ()
449 = do dflags <- getDynFlags
450 if hscLang dflags == HscInterpreted && n > 0
451 then putStr "warning: -O conflicts with --interactive; -O ignored.\n"
452 else updDynFlags (setOptLevel' n)
456 then dfs2{ hscLang = HscC, optLevel = n } -- turn on -fvia-C with -O
457 else dfs2{ optLevel = n }
459 dfs1 = foldr (flip dopt_unset) dfs remove_dopts
460 dfs2 = foldr (flip dopt_set) dfs1 extra_dopts
463 | n == 0 = opt_0_dopts
464 | otherwise = opt_1_dopts
467 | n == 0 = opt_1_dopts
468 | otherwise = opt_0_dopts
471 Opt_IgnoreInterfacePragmas,
472 Opt_OmitInterfacePragmas
481 -- Core-to-core phases:
483 buildCoreToDo :: DynFlags -> [CoreToDo]
484 buildCoreToDo dflags = core_todo
486 opt_level = optLevel dflags
487 max_iter = maxSimplIterations dflags
488 strictness = dopt Opt_Strictness dflags
489 full_laziness = dopt Opt_FullLaziness dflags
490 cse = dopt Opt_CSE dflags
491 rule_check = ruleCheck dflags
494 if opt_level == 0 then
496 CoreDoSimplify (SimplPhase 0) [
497 MaxSimplifierIterations max_iter
501 else {- opt_level >= 1 -} [
503 -- initial simplify: mk specialiser happy: minimum effort please
504 CoreDoSimplify SimplGently [
506 -- Don't inline anything till full laziness has bitten
507 -- In particular, inlining wrappers inhibits floating
508 -- e.g. ...(case f x of ...)...
509 -- ==> ...(case (case x of I# x# -> fw x#) of ...)...
510 -- ==> ...(case x of I# x# -> case fw x# of ...)...
511 -- and now the redex (f x) isn't floatable any more
512 -- Similarly, don't apply any rules until after full
513 -- laziness. Notably, list fusion can prevent floating.
516 -- Don't do case-of-case transformations.
517 -- This makes full laziness work better
518 MaxSimplifierIterations max_iter
521 -- Specialisation is best done before full laziness
522 -- so that overloaded functions have all their dictionary lambdas manifest
525 if full_laziness then CoreDoFloatOutwards (FloatOutSw False False)
530 CoreDoSimplify (SimplPhase 2) [
531 -- Want to run with inline phase 2 after the specialiser to give
532 -- maximum chance for fusion to work before we inline build/augment
533 -- in phase 1. This made a difference in 'ansi' where an
534 -- overloaded function wasn't inlined till too late.
535 MaxSimplifierIterations max_iter
537 case rule_check of { Just pat -> CoreDoRuleCheck 2 pat; Nothing -> CoreDoNothing },
539 CoreDoSimplify (SimplPhase 1) [
540 -- Need inline-phase2 here so that build/augment get
541 -- inlined. I found that spectral/hartel/genfft lost some useful
542 -- strictness in the function sumcode' if augment is not inlined
543 -- before strictness analysis runs
544 MaxSimplifierIterations max_iter
546 case rule_check of { Just pat -> CoreDoRuleCheck 1 pat; Nothing -> CoreDoNothing },
548 CoreDoSimplify (SimplPhase 0) [
549 -- Phase 0: allow all Ids to be inlined now
550 -- This gets foldr inlined before strictness analysis
552 MaxSimplifierIterations 3
553 -- At least 3 iterations because otherwise we land up with
554 -- huge dead expressions because of an infelicity in the
556 -- let k = BIG in foldr k z xs
557 -- ==> let k = BIG in letrec go = \xs -> ...(k x).... in go xs
558 -- ==> let k = BIG in letrec go = \xs -> ...(BIG x).... in go xs
562 case rule_check of { Just pat -> CoreDoRuleCheck 0 pat; Nothing -> CoreDoNothing },
564 #ifdef OLD_STRICTNESS
567 if strictness then CoreDoStrictness else CoreDoNothing,
571 CoreDoSimplify (SimplPhase 0) [
572 MaxSimplifierIterations max_iter
575 if full_laziness then
576 CoreDoFloatOutwards (FloatOutSw False -- Not lambdas
577 True) -- Float constants
579 -- nofib/spectral/hartel/wang doubles in speed if you
580 -- do full laziness late in the day. It only happens
581 -- after fusion and other stuff, so the early pass doesn't
582 -- catch it. For the record, the redex is
583 -- f_el22 (f_el21 r_midblock)
586 -- We want CSE to follow the final full-laziness pass, because it may
587 -- succeed in commoning up things floated out by full laziness.
588 -- CSE used to rely on the no-shadowing invariant, but it doesn't any more
590 if cse then CoreCSE else CoreDoNothing,
594 -- Case-liberation for -O2. This should be after
595 -- strictness analysis and the simplification which follows it.
597 case rule_check of { Just pat -> CoreDoRuleCheck 0 pat; Nothing -> CoreDoNothing },
599 if opt_level >= 2 then
603 if opt_level >= 2 then
608 -- Final clean-up simplification:
609 CoreDoSimplify (SimplPhase 0) [
610 MaxSimplifierIterations max_iter
614 -- --------------------------------------------------------------------------
615 -- Mess about with the mutable variables holding the dynamic arguments
618 -- is the "baseline" dynamic flags, initialised from
619 -- the defaults and command line options, and updated by the
620 -- ':s' command in GHCi.
623 -- is the dynamic flags for the current compilation. It is reset
624 -- to the value of v_InitDynFlags before each compilation, then
625 -- updated by reading any OPTIONS pragma in the current module.
627 GLOBAL_VAR(v_InitDynFlags, defaultDynFlags, DynFlags)
628 GLOBAL_VAR(v_DynFlags, defaultDynFlags, DynFlags)
630 setDynFlags :: DynFlags -> IO ()
631 setDynFlags dfs = writeIORef v_DynFlags dfs
633 saveDynFlags :: IO ()
634 saveDynFlags = do dfs <- readIORef v_DynFlags
635 writeIORef v_InitDynFlags dfs
637 restoreDynFlags :: IO DynFlags
638 restoreDynFlags = do dfs <- readIORef v_InitDynFlags
639 writeIORef v_DynFlags dfs
642 getDynFlags :: IO DynFlags
643 getDynFlags = readIORef v_DynFlags
645 updDynFlags :: (DynFlags -> DynFlags) -> IO ()
646 updDynFlags f = do dfs <- readIORef v_DynFlags
647 writeIORef v_DynFlags (f dfs)
649 dynFlag :: (DynFlags -> a) -> IO a
650 dynFlag f = do dflags <- readIORef v_DynFlags; return (f dflags)
652 setDynFlag, unSetDynFlag :: DynFlag -> IO ()
653 setDynFlag f = updDynFlags (\dfs -> dopt_set dfs f)
654 unSetDynFlag f = updDynFlags (\dfs -> dopt_unset dfs f)
658 %************************************************************************
660 \subsection{Warnings}
662 %************************************************************************
666 = [ Opt_WarnDeprecations,
667 Opt_WarnOverlappingPatterns,
668 Opt_WarnMissingFields,
669 Opt_WarnMissingMethods,
670 Opt_WarnDuplicateExports
674 = standardWarnings ++
675 [ Opt_WarnUnusedBinds,
676 Opt_WarnUnusedMatches,
677 Opt_WarnUnusedImports,
678 Opt_WarnIncompletePatterns,
684 [ Opt_WarnTypeDefaults,
685 Opt_WarnNameShadowing,
691 %************************************************************************
693 \subsection{Classifying command-line options}
695 %************************************************************************
698 -- v_Statis_hsc_opts is here to avoid a circular dependency with
700 GLOBAL_VAR(v_Static_hsc_opts, [], [String])
702 lookUp :: FastString -> Bool
703 lookup_int :: String -> Maybe Int
704 lookup_def_int :: String -> Int -> Int
705 lookup_def_float :: String -> Float -> Float
706 lookup_str :: String -> Maybe String
708 unpacked_static_opts = unsafePerformIO (readIORef v_Static_hsc_opts)
709 packed_static_opts = map mkFastString unpacked_static_opts
711 lookUp sw = sw `elem` packed_static_opts
713 -- (lookup_str "foo") looks for the flag -foo=X or -fooX,
714 -- and returns the string X
716 = case firstJust (map (startsWith sw) unpacked_static_opts) of
717 Just ('=' : str) -> Just str
721 lookup_int sw = case (lookup_str sw) of
723 Just xx -> Just (try_read sw xx)
725 lookup_def_int sw def = case (lookup_str sw) of
726 Nothing -> def -- Use default
727 Just xx -> try_read sw xx
729 lookup_def_float sw def = case (lookup_str sw) of
730 Nothing -> def -- Use default
731 Just xx -> try_read sw xx
734 try_read :: Read a => String -> String -> a
735 -- (try_read sw str) tries to read s; if it fails, it
736 -- bleats about flag sw
739 ((x,_):_) -> x -- Be forgiving: ignore trailing goop, and alternative parses
740 [] -> ghcError (UsageError ("Malformed argument " ++ str ++ " for flag " ++ sw))
741 -- ToDo: hack alert. We should really parse the arugments
742 -- and announce errors in a more civilised way.
746 Putting the compiler options into temporary at-files
747 may turn out to be necessary later on if we turn hsc into
748 a pure Win32 application where I think there's a command-line
749 length limit of 255. unpacked_opts understands the @ option.
751 unpacked_opts :: [String]
755 map unpackFS argv -- NOT ARGV any more: v_Static_hsc_opts
757 expandAts ('@':fname) = words (unsafePerformIO (readFile fname))
762 %************************************************************************
764 \subsection{Static options}
766 %************************************************************************
770 opt_PprStyle_Debug = lookUp FSLIT("-dppr-debug")
771 opt_PprUserLength = lookup_def_int "-dppr-user-length" 5 --ToDo: give this a name
774 opt_AutoSccsOnAllToplevs = lookUp FSLIT("-fauto-sccs-on-all-toplevs")
775 opt_AutoSccsOnExportedToplevs = lookUp FSLIT("-fauto-sccs-on-exported-toplevs")
776 opt_AutoSccsOnIndividualCafs = lookUp FSLIT("-fauto-sccs-on-individual-cafs")
777 opt_SccProfilingOn = lookUp FSLIT("-fscc-profiling")
778 opt_DoTickyProfiling = lookUp FSLIT("-fticky-ticky")
781 opt_AllStrict = lookUp FSLIT("-fall-strict")
782 opt_DictsStrict = lookUp FSLIT("-fdicts-strict")
783 opt_IrrefutableTuples = lookUp FSLIT("-firrefutable-tuples")
784 opt_MaxContextReductionDepth = lookup_def_int "-fcontext-stack" mAX_CONTEXT_REDUCTION_DEPTH
785 opt_Parallel = lookUp FSLIT("-fparallel")
786 opt_SMP = lookUp FSLIT("-fsmp")
787 opt_Flatten = lookUp FSLIT("-fflatten")
790 opt_NoStateHack = lookUp FSLIT("-fno-state-hack")
791 opt_NoMethodSharing = lookUp FSLIT("-fno-method-sharing")
792 opt_CprOff = lookUp FSLIT("-fcpr-off")
793 opt_RulesOff = lookUp FSLIT("-frules-off")
794 -- Switch off CPR analysis in the new demand analyser
795 opt_LiberateCaseThreshold = lookup_def_int "-fliberate-case-threshold" (10::Int)
796 opt_MaxWorkerArgs = lookup_def_int "-fmax-worker-args" (10::Int)
799 The optional '-inpackage=P' flag tells what package
800 we are compiling this module for.
801 The Prelude, for example is compiled with '-inpackage std'
803 opt_InPackage = case lookup_str "-inpackage=" of
804 Just p -> mkFastString p
805 Nothing -> FSLIT("Main") -- The package name if none is specified
807 opt_EmitCExternDecls = lookUp FSLIT("-femit-extern-decls")
808 opt_EnsureSplittableC = lookUp FSLIT("-fglobalise-toplev-names")
809 opt_GranMacros = lookUp FSLIT("-fgransim")
810 opt_HiVersion = read (cProjectVersionInt ++ cProjectPatchLevel) :: Int
811 opt_HistorySize = lookup_def_int "-fhistory-size" 20
812 opt_OmitBlackHoling = lookUp FSLIT("-dno-black-holing")
813 opt_RuntimeTypes = lookUp FSLIT("-fruntime-types")
815 -- Simplifier switches
816 opt_SimplNoPreInlining = lookUp FSLIT("-fno-pre-inlining")
817 -- NoPreInlining is there just to see how bad things
818 -- get if you don't do it!
819 opt_SimplExcessPrecision = lookUp FSLIT("-fexcess-precision")
822 opt_UF_CreationThreshold = lookup_def_int "-funfolding-creation-threshold" (45::Int)
823 opt_UF_UseThreshold = lookup_def_int "-funfolding-use-threshold" (8::Int) -- Discounts can be big
824 opt_UF_FunAppDiscount = lookup_def_int "-funfolding-fun-discount" (6::Int) -- It's great to inline a fn
825 opt_UF_KeenessFactor = lookup_def_float "-funfolding-keeness-factor" (1.5::Float)
826 opt_UF_UpdateInPlace = lookUp FSLIT("-funfolding-update-in-place")
828 opt_UF_DearOp = ( 4 :: Int)
830 opt_Static = lookUp FSLIT("-static")
831 opt_Unregisterised = lookUp FSLIT("-funregisterised")
832 opt_EmitExternalCore = lookUp FSLIT("-fext-core")
834 -- Include full span info in error messages, instead of just the start position.
835 opt_ErrorSpans = lookUp FSLIT("-ferror-spans")
837 opt_PIC = lookUp FSLIT("-fPIC")
840 %************************************************************************
842 \subsection{List of static hsc flags}
844 %************************************************************************
849 "fauto-sccs-on-all-toplevs",
850 "fauto-sccs-on-exported-toplevs",
851 "fauto-sccs-on-individual-cafs",
852 "fauto-sccs-on-dicts",
857 "firrefutable-tuples",
863 "femit-extern-decls",
864 "fglobalise-toplev-names",
866 "fno-hi-version-check",
868 "fno-method-sharing",
873 "funfolding-update-in-place",
883 || any (flip prefixMatch f) [
885 "fliberate-case-threshold",
888 "funfolding-creation-threshold",
889 "funfolding-use-threshold",
890 "funfolding-fun-discount",
891 "funfolding-keeness-factor"
895 %************************************************************************
897 \subsection{Misc functions for command-line options}
899 %************************************************************************
904 startsWith :: String -> String -> Maybe String
905 -- startsWith pfx (pfx++rest) = Just rest
907 startsWith [] str = Just str
908 startsWith (c:cs) (s:ss)
909 = if c /= s then Nothing else startsWith cs ss
910 startsWith _ [] = Nothing
912 endsWith :: String -> String -> Maybe String
914 = case (startsWith (reverse cs) (reverse ss)) of
916 Just rs -> Just (reverse rs)