The attached file MonadLibrary.lhs compiles without optimization, but with
optimization on the following message is printed:

lips> ghc-4.04 -O -c -fglasgow-exts MonadLibrary.lhs

  panic! (the `impossible' happened):
          mk_cpr_let: not a product
      forall a{-ruq-} b{-rur-}.
      (a{-ruq-} -> b{-rur-})
      -> MonadLibrary.StateM{-r2o,x-} m{-a30Y-} s{-a30Z-} a{-ruq-}
      -> MonadLibrary.StateM{-r2o,x-} m{-a30Y-} s{-a30Z-} b{-rur-}

  Please report it as a compiler bug to [EMAIL PROTECTED]

I downloaded the binary distribution from

 
http://research.microsoft.com/users/t-simonm/ghc/dist/4.04/ghc-4.04-sparc-sun-solaris2.tar.g

More details follow, and the full sourcecode for the imported modules are
attached.

Patrik Jansson

----------------------------------------------------------------
lips> uname -a
SunOS lips.cs.chalmers.se 5.6 Generic_105181-12 sun4u sparc SUNW,Ultra-4
lips> ghc-4.04 -v -O -c -fglasgow-exts MonadLibrary.lhs >& err
lips> cat err 
The Glorious Glasgow Haskell Compilation System, version 4.04, patchlevel 0

literate pre-processor:
        /usr/pd/lib/ghc-4.04/unlit  MonadLibrary.lhs -  >> /tmp/ghc2828.lpp

real        0.0
user        0.0
sys         0.0

Effective command line: -v -O -c -fglasgow-exts

Ineffective C pre-processor:
        echo '{-# LINE 1 "MonadLibrary.lhs" -}' > /tmp/ghc2828.cpp && cat 
/tmp/ghc2828.lpp >> /tmp/ghc2828.cpp

real        0.0
user        0.0
sys         0.0

Haskell compiler:
        /usr/pd/lib/ghc-4.04/hsc /tmp/ghc2828.cpp  -fglasgow-exts -ffoldr-build-on 
-fdo-eta-reduction -fdo-lambda-eta-expansion -fcase-of-case -fcase-merge -flet-to-case 
-fpedantic-bottoms -fsimplify [ -finline-phase0 -fmax-simplifier-iterations2 ] 
-fspecialise -ffull-laziness -ffloat-inwards -fsimplify [ -finline-phase1 
-fmax-simplifier-iterations4 ]  -fsimplify [ -finline-phase2 
-fmax-simplifier-iterations4 ] -fstrictness -fcpr-analyse -fworker-wrapper -fsimplify 
[ -fmax-simplifier-iterations4 ] -fcse -ffull-laziness -ffloat-inwards -fsimplify [ 
-fmax-simplifier-iterations4 ]   -flet-no-escape -fwarn-overlapping-patterns 
-fwarn-missing-methods -fwarn-duplicate-exports -fhi-version=404 -static 
-himap=.%.hi:/usr/pd/lib/ghc-4.04/imports/exts%.hi:/usr/pd/lib/ghc-4.04/imports/exts%.hi:/usr/pd/lib/ghc-4.04/imports/std%.hi
    -v -hifile=/tmp/ghc2828.hi -C=/tmp/ghc2828.hc -F=/tmp/ghc2828_stb.c 
-FH=/tmp/ghc2828_stb.h +RTS -H6000000 -K1000000
Glasgow Haskell Compiler, version 4.04, for Haskell 98, compiled by GHC version 4.04

panic! (the `impossible' happened):
        mk_cpr_let: not a product
    forall a{-ruq-} b{-rur-}.
    (a{-ruq-} -> b{-rur-})
    -> MonadLibrary.StateM{-r2o,x-} m{-a30Y-} s{-a30Z-} a{-ruq-}
    -> MonadLibrary.StateM{-r2o,x-} m{-a30Y-} s{-a30Z-} b{-rur-}

Please report it as a compiler bug to [EMAIL PROTECTED]



real        4.8
user        4.6
sys         0.1
deleting... /tmp/ghc2828.lpp /tmp/ghc2828.cpp /tmp/ghc2828.hi /tmp/ghc2828.hc 
/tmp/ghc2828_stb.c /tmp/ghc2828_stb.h

rm -f /tmp/ghc2828*

-----------------------------------------------
PS. when compiling the same module without -O I do get warnings, but I
    guess these are unrelated to the above problem.

lips> ghc-4.04  -c -fglasgow-exts MonadLibrary.lhs
ghc-4.04: module version changed to 1; reason: no old .hi file
/tmp/ghc2720.hc:316: warning: `s4tO_closure' was declared `extern' and
later `static'
/tmp/ghc2720.hc:1123: warning: `s4ub_closure' was declared `extern' and
later `static'
/tmp/ghc2720.hc:3713: warning: `s4uU_closure' was declared `extern' and
later `static'

\chapter{Monad library}
\begin{verbatim}

> module MonadLibrary(module StateFix,
>                     State     ,updateST ,fetchST ,executeST ,
>                     StateM(..),updateSTM,fetchSTM,executeSTM,mliftSTM,
>                     (<@),(<@-),(<*>),(<:*>),(<<),(@@),(<|),(+++),mIf,
>                     applyM,applyM2,
>                     Error(..),unDone,noErrorFilter,errorToList,
>                     LErr,unLErr,mapLErr,showLErr,handleError,
>                     STErr,mliftErr,convertSTErr,ErrorMonad(failEM),
>                     changeError,
>                     OutputT,output,runOutput,mliftOut,
>                     mapl,foreach,liftop,map0,map1,map2,mfoldl,mfoldr,
>                     mZero,mplus,
>                     accumseq,accumseq_,mguard) where
> import StateFix
> import MyPrelude(pair,mapFst,fMap)


> import Monad(MonadPlus(..),join)






> infixl 9 <@
> infixl 9 <@-
> infixr 9 @@
> infixr 9 <*>
> infixl 7 <|
> infixr 5 +++
> infixr 1 <<

> mZero :: MonadPlus m => m a

> mZero = mzero


> mguard :: MonadPlus m => Bool -> m ()
> mguard b = if b then return () else mZero

> (+++) :: MonadPlus m => m a -> m a -> m a
> (+++) = mplus

\end{verbatim}
\section{Monad based utilities}

Function \texttt{accumseq} is called \texttt{sequence} in Haskell 98
but earlier \textt{accumulate}.

\begin{verbatim}

> accumseq :: Monad m => [m a] -> m [a]
> accumseq = mapM id
> accumseq_ :: Monad m => [m a] -> m ()
> accumseq_ = foldr (>>) (return ())

> (<@) :: Functor f => f a -> (a -> b) -> f b
> x <@ f  = fMap f x
> (<@-) :: Functor f => f a -> b -> f b
> x <@- e = fMap (\_->e) x

join      :: Monad m => m (m a) -> m a
join x     = x >>= id



Removed from the prelude: (renamed to (=<<))

> applyM :: Monad m => (a -> m b) -> m a -> m b
> applyM = flip (>>=)



> applyM2 :: Monad m => (a -> b -> m c) -> m a -> m b -> m c
> applyM2 f ma mb = ma >>= \a -> mb >>= \b -> f a b
> --applyM2 f ma mb = ma >>= (mb >>=) . f

> (@@) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
> (@@) f g x        = g x >>= f

The original LHS: {\tt (f @@ g) x} proves not to be allowed by
Haskell 1.4. (Though it should be, in my opinion.) It is OK in Haskell 98.

> mfoldl           :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
> mfoldl _ a []     = return a
> mfoldl f a (x:xs) = f a x >>= (\fax -> mfoldl f fax xs)

> mfoldr           :: Monad m => (a -> b -> m b) -> b -> [a] -> m b
> mfoldr _ a []     = return a
> mfoldr f a (x:xs) = mfoldr f a xs >>= (\y -> f x y)

> mapl             :: Monad m => (a -> m b) -> ([a] -> m [b])
> mapl _ []         = return [] 
> mapl f (x:xs)     = f x >>= \y -> mapl f xs >>= \ys -> return (y:ys) 

> mapr             :: Monad m => (a -> m b) -> ([a] -> m [b])
> mapr _ []         = return []
> mapr f (x:xs)     = mapr f xs >>= \ys -> f x >>= \y-> return (y:ys) 

> mIf :: Monad m => m Bool -> m a -> m a -> m a
> mIf mb t f = mb >>= \b-> if b then t else f

> (<|) :: MonadPlus m => m a -> (a -> Bool) -> m a
> m <| p = m >>= \x -> if p x then return x else mZero

\end{verbatim}
\section{IO and ST monads}
Hugs:
\begin{verbatim}
instance Functor (ST a) where
  map f sta = sta `thenST` \a -> return (f a)
\end{verbatim}
\section{Error monad}
\begin{verbatim}

> class Monad m => ErrorMonad m where
>   failEM :: String -> m a

> data Error a = Done a
>              | Err String
>              deriving (Show, Eq)


> instance Functor Error where
>   fmap f (Done x) = Done (f x)
>   fmap _ (Err s)  = Err s

> instance Monad Error where
>     return         = Done
>     Done x  >>= f  = f x
>     Err msg >>= _  = Err msg

> instance ErrorMonad Error where
>   failEM = Err

> unDone :: Error a -> a
> unDone (Done x) = x
> unDone (Err s) = error s

> type LErr a = (a,Error ())

> showLErr :: Show a => LErr a -> String
> showLErr (x,err) = show x ++ handleError id (fMap (\_->"") err)

> mapLErr :: (a->b) -> LErr a -> LErr b
> mapLErr = mapFst

> unLErr :: LErr a -> a
> unLErr = handleLErr (error.("MonadLibrary.handleLErr:"++))

> handleLErr :: (String -> a) -> LErr a -> a
> handleLErr _   (x,Done ()) = x
> handleLErr def (_,Err msg) = def msg

> handleError :: (String -> a) -> Error a -> a
> handleError d = h
>   where h (Done x)   = x
>         h (Err mess) = d mess

> errorToList :: Error a -> [a]
> errorToList (Err msg) = []
> errorToList (Done x)  = [x]

> noErrorFilter :: [Error a] -> [a]
> noErrorFilter = concatMap errorToList

> instance ErrorMonad [] where
>   failEM _ = []

\end{verbatim}
\section{IOErr monad}
\begin{verbatim}

> newtype IOErr a = IOErr (IO (Error a)) 
>   {- in mapIOE, returnIOE, bindIOE, failIOE,
>         liftIOtoIOErr, dropIOErrtoIO, dropError -}
> 
> mapIOE :: (a -> b) -> (IOErr a) -> (IOErr b)
> mapIOE f (IOErr xs) = IOErr (xs <@ fMap f)
> 
> instance Functor IOErr where   
>   fmap = mapIOE
> 
> returnIOE :: a -> IOErr a 
> returnIOE x = IOErr (return (Done x))
> 
> bindIOE :: IOErr a -> (a -> IOErr b) -> IOErr b
> (IOErr xs) `bindIOE` f 
>   = IOErr (xs >>= \x ->
>            case x of
>              Done a  -> unIOErr (f a)
>              Err msg -> return (Err msg)
>           )
>     where unIOErr (IOErr x) = x
> 
> instance Monad IOErr where
>   return = returnIOE
>   (>>=)   = bindIOE
> 
> failIOE :: String -> IOErr a
> failIOE msg = IOErr (return (Err msg))
> 
> instance ErrorMonad IOErr where
>   failEM = failIOE
> 
> {-
> liftIOtoIOErr :: IO a -> IOErr a
> liftIOtoIOErr = IOErr . fMap Done
> 
> dropIOErrtoIO :: IOErr a -> IO a
> dropIOErrtoIO (IOErr m)
>     = m >>= \x -> 
>       case x of 
>         Done a  -> return a
>         Err msg -> putErrStrLn msg  >>
>                    error "drop!" -- return undefined
> 
> dropError :: IOErr a -> IO b -> (a -> IO b) -> IO b
> dropError (IOErr m) failure success
>   = m >>= \x -> 
>     case x of 
>       Done a  -> success a
>       Err msg -> putErrStrLn msg >> failure
> -}

\end{verbatim}
\section{STErr monad}
\begin{verbatim}
 
> newtype STErr s a = STErr (ST s (Error a))
>  {- in mapSTE,returnSTE,bindSTE,failSTE,liftSTtoSTErr,
>        dropSTErrtoST,dropErrorST,convertSTErr -}
> 
> mapSTE :: (a -> b) -> (STErr s a) -> (STErr s b)
> mapSTE f (STErr xs) = STErr (xs <@ fMap f)
> 
> instance Functor (STErr s) where   
>   fmap = mapSTE
> 
> returnSTE :: a -> STErr s a 
> returnSTE x = STErr (return (Done x))
> 
> bindSTE :: STErr s a -> (a -> STErr s b) -> STErr s b
> (STErr xs) `bindSTE` f 
>   = STErr (xs >>= \x ->
>            case x of
>              Done a  -> convertSTErr (f a)
>              Err msg -> return (Err msg)
>           )
> 
> instance Monad (STErr s) where
>   return = returnSTE
>   (>>=)  = bindSTE
> 
> failSTE :: String -> STErr s a
> failSTE msg = STErr (return (Err msg))
> 
> instance ErrorMonad (STErr s) where
>   failEM = failSTE
> 
> changeError :: (String -> String) -> STErr s a -> STErr s a
> changeError f (STErr m) = STErr $ m >>= \e-> case e of
>                               Done x -> return (Done x)
>                               Err msg-> return (Err (f msg))
> 
> liftSTtoSTErr :: ST s a -> STErr s a
> liftSTtoSTErr = STErr . fMap Done
> 
> mzeroSTErr = STErr (return (Err "mzero:"))
>
> instance MonadPlus (STErr s) where

>   mzero  = mzeroSTErr



>   a `mplus` b = STErr $ 
>     convertSTErr a >>= \x -> case x of
>       Done y -> return (Done y)
>       Err _  -> convertSTErr b

> {- 
> dropSTErrtoST :: STErr s a -> ST s a
> dropSTErrtoST (STErr m)
>     = m >>= \x -> 
>       case x of 
>         Done a  -> return a
>         Err msg -> error ("dropSTErrtoST: "++msg)
> 
> 
> dropErrorST :: STErr s a -> (String -> ST s b) -> (a -> ST s b) -> ST s b
> dropErrorST (STErr m) failure success
>   = m >>= \x -> 
>     case x of 
>       Done a  -> success a
>       Err msg -> failure msg
> -}
> 
> convertSTErr :: STErr s a -> ST s (Error a)
> convertSTErr (STErr x) = x

\end{verbatim}
\section{State monad}
\begin{verbatim}

> data State s a = ST (s -> (a,s))
> 
> instance Functor (State s) where
>   fmap f (ST st) = 
>     ST (\s -> let {(x,s') = st s} in (f x, s'))
> 
> instance Monad (State s) where
>   return x   = ST (\s -> (x,s))
>   ST m >>= f = ST (\s -> let (x,s') = m s
>                              ST f'  = f x
>                          in  f' s')
> 
> updateST :: (s->s) -> State s s
> updateST f = ST (\s -> (s, f s))
> fetchST :: State s s
> fetchST = updateST id
> 
> executeST :: s -> State s a -> a
> executeST s (ST m) = a where (a,_) = m s

\end{verbatim}
\section{STM monad}
\begin{verbatim}

> data StateM m s a = STM (s -> m (a,s)) 
> 
> instance Functor m => Functor (StateM m s) where
>   fmap f (STM xs) = 
>     STM (\s -> fMap (\(x,s') -> (f x, s')) 
>                     (xs s)                                
>         )                                 
> instance Monad m => Monad (StateM m s) where
>   return x        = STM (\s -> return (x,s))
>   STM xs >>= f = STM (\s -> xs s >>= \(x, s') ->
>                                let STM f' = f x
>                                in f' s'
>                         )  
>
> mZeroSTM :: MonadPlus m => StateM m s a
> mZeroSTM = STM (\_ -> mZero)
>

> instance MonadPlus m => MonadPlus (StateM m s) where
>   mzero = mZeroSTM
>   mplus (STM stm) (STM stm') = STM (\s -> stm s +++ stm' s)

> 
> instance ErrorMonad m => ErrorMonad (StateM m s) where
>   failEM msg = STM (\_ -> failEM msg)
> 
> updateSTM :: Monad m => (s->s) -> StateM m s s
> updateSTM f = STM (\s -> return (s, f s))
> 
> fetchSTM :: Monad m => StateM m a a
> fetchSTM = updateSTM id
> 
> executeSTM :: Monad m => s -> StateM m s a -> m a
> executeSTM s (STM m) = m s >>=  \ ~(x,_) -> return x

\end{verbatim}
\section{Conversions between monads}
\begin{verbatim}

> mliftErr :: ST s a -> STErr s a
> mliftErr = liftSTtoSTErr
> 
> mliftSTM :: Functor f => f a -> StateM f s a
> mliftSTM m = STM (\s -> fMap (`pair` s) m)

> mliftOut :: Functor m => m a -> OutputT b m a
> mliftOut ma = OT (fMap return ma)

\end{verbatim}
\section{Operations on all monads}
\begin{verbatim}

> foreach :: Monad m => [a] -> (a -> m b) -> m [b]
> foreach = flip mapl
> 
> loop :: Monad m => [a -> m a] -> a -> m a
> loop []     x = return x
> loop (f:fs) x = f x >>= \y -> 
>                 loop fs y

> (<*>) :: Monad m => m a -> m b -> m (a,b)
> (<*>) = liftop pair

> (<:*>) :: Monad m => m a -> m [a] -> m [a] 
> (<:*>) = liftop (:)

> (<<) :: Monad m => m a -> m b -> m a
> (<<) = liftop const

\end{verbatim}
\subsection{More monad utilities}
Some other functions used in the following. \verb|liftop| does for an
operator what \verb|map| (on a monad) does for a function. 
\begin{verbatim}

> liftop :: Monad m   => (a -> b -> c)  ->  m a -> m b -> m c
> map2   :: Monad m   => (a -> b -> c)  ->  m a -> m b -> m c
> map1   :: Functor m => (a -> b)       ->  m a -> m b 
> map0   :: Monad m   => a              ->  m a

\end{verbatim}
The order of the \verb|bind|s is important. (Swap them and the parser
will be a nice left recursive black hole;-)
\begin{verbatim}

> liftop f mp mq=mp >>= \p-> mq >>= \q-> return (f p q)
> map2 = liftop
> map1 = fMap
> map0 = return

\end{verbatim}
\section{Writer and output monads}
\begin{verbatim}

> data Writer a b = Writer ([a]->[a]) b
> instance Functor (Writer a) where
>   fmap f (Writer s x) = Writer s (f x)
> instance Monad (Writer a) where
>   return = Writer id
>   (Writer s a) >>= f = Writer (s.t) b
>               where Writer t b = f a

> write :: a -> Writer a ()
> write x = Writer (x:) ()

> data OutputT a m b = OT (m (Writer a b))

> unOT :: (OutputT a m b) -> m (Writer a b)
> unOT (OT m) = m

> instance Functor m => Functor (OutputT a m) where
>   fmap f (OT mx) = OT (fMap (fMap f) mx)

> instance (Functor m ,Monad m) => Monad (OutputT a m) where
>   return x     = OT (return (return x))
>   (OT m) >>= f = OT ((fMap join . join . fMap f') m)
>        where f' = swap . fMap (unOT . f)
>              swap (Writer s ma) = fMap (Writer s) ma

> output :: Monad m => a -> OutputT a m ()
> output x = OT (return (write x))

> runOutput' :: Functor m => OutputT a m b -> m ([a] -> [a],b)
> runOutput' (OT m) = fMap (\(Writer s a) -> (s,a)) m

> runOutput :: Functor m => [a] -> OutputT a m b -> m ([a],b)
> runOutput l o = fMap (\(s,x)->(s l,x)) (runOutput' o)

\end{verbatim}

\section{Mutable variables}

This module serves as a glue between the rest of the PolyP
implementation and the varying implementations of the ST-monad.  As
the ST-monad is a Haskell extension, the interface has not yet
settled.

The differences are of two kinds:
\begin{itemize}
\item Different names of the new functions (easy to fix):\\
  The names used in the rest of PolyP are those that were earlier used
  in hugs and still are used in hbc [980428].
  
\item Different ways of extending the type system to deal with
  \texttt{runST} (harder to fix):\\
  In hugs, \texttt{runST} is a keyword and not a function, which means
  that it can not be renamed and it can not even be mentioned in the
  import or export lists. In hbc, a special constructor \texttt{RunST}
  is used in concert with (the normal function) \texttt{runST}. And in
  ghc \texttt{runST} is a normal function. (Provided the flag
  \texttt{-fglasgow-exts} is used when compiling.)
\end{itemize}

\begin{verbatim}


> module StateFix(module ST,MutVar,newVar,readVar,writeVar,(===),
>                 MutArr,newArr,readArr,writeArr) where
> import ST -- (ST,STRef,runST,newSTRef,readSTRef,writeSTRef)



In Haskell 98 the class Ix is in a separate module instead of in the
  prelude.  (The change was discovered when moving from ghc-4.02 to
  ghc-4.03 thus the prelude in ghc-4.02 is wrong.)


> import Ix(Ix)






> type MutArr s a b = STArray s a b
> type MutVar s a = STRef s a

> newVar   ::               a -> ST s (MutVar s a)
> readVar  :: MutVar a b ->      ST a b
> writeVar :: MutVar a b -> b -> ST a ()

> newVar  = newSTRef     
> readVar = readSTRef
> writeVar= writeSTRef




\end{verbatim}
Due to problems with combining overloading with the \verb|ST s|-monad
(in particular the construct \verb|runST|) we will use a special
symbol (the triple equality sign symbol, \verb|===|) for pointer
equality. 
\begin{verbatim}

> (===) :: MutVar s a -> MutVar s a -> Bool

> (===) = (==)    -- Pointer equality




\end{verbatim}
\section{Mutable arrays}
\begin{verbatim}


> newArr       :: Ix a => (a,a) -> b -> ST s (MutArr s a b)
> readArr      :: Ix a => MutArr s a b -> a -> ST s b
> writeArr     :: Ix a => MutArr s a b -> a -> b -> ST s ()

> newArr   = newSTArray
> readArr  = readSTArray
> writeArr = writeSTArray




\end{verbatim}
\chapter{Prelude-like functions}
\begin{verbatim}

> module MyPrelude(module MyPrelude,trace) where
> import NonStdTrace(trace)
> import qualified IO(hFlush,hPutStr,stdout,stderr)
> import Flags(Flags(..),flags)
> import System(exitWith,ExitCode(..))

\end{verbatim}
\section{Error messages}

\begin{verbatim}

> stopNow :: IO a
> stopNow = exitWith ExitSuccess

> fatalError :: String -> IO a
> fatalError s = IO.hPutStr IO.stderr ("PolyP ERROR: "++s) >> exitWith (ExitFailure 1)

> putErrStr   :: String -> IO ()
> putErrStrLn :: String -> IO ()

> putErrStr   = if verbose flags 
>               then IO.hPutStr   IO.stderr 
>               else const (return ())
> putErrStrLn s = putErrStr (s++"\n")


> putStrNow :: String -> IO ()
> putStrNow s = putStr s >> IO.hFlush IO.stdout

\end{verbatim}

\section{Compatibility issues}

In Haskell 98 what was earlier \texttt{map} has been split into two 
values: one class member \texttt{fmap} and one list map \texttt{map}.
To achieve backward compatibility we define \texttt{fMap} even for 
earlier Haskell versions.

> fMap :: Functor f => (a->b) -> f a -> f b
> fMap = fmap

\section{Some list utilities}

\begin{verbatim}

> flatMap :: (a -> [b]) -> [a] -> [b]
> without :: Eq a => [a] -> [a] -> [a]
> withoutBy:: (a -> a -> Bool) -> [a] -> [a] -> [a]
> splitUp :: [a -> Bool] -> [a] -> [[a]]
> unique  :: Eq a => [a] -> [a]
> combineUniqueBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]

\end{verbatim}
Given an equality function and two lists qs and xs where the first
list contains no duplicates, {\tt combineUniqueBy} gives a sublist ys
of xs such that qs++ys contains no duplicates.

The function {\tt flatMap} maps a function (returning a list
instead of just one element) over a list and concatenates the 
resulting lists afterwards.

The function {\tt without} removes all occurrences of elements in the
second list from the first list; 
e.g. {\tt [1,2,3,3,4] `without` [1,3] = [2,4]}

The function {\tt splitUp} splits up a list according to a list of 
predicates. The resulting list of lists has a length that is one
more than the list of predicates. The last list is used to store
all elements that don't satisfy any of the predicates;
e.g. {\tt splitUp [(>3), (<2)] [1..5] = [[4,5], [1], [2,3]]}.

\subsection{Maybe}
The {\tt Maybe} data type is used whenever a function is not certain
to return a value (for example in environment lookups). \verb|Maybe|
is a functor and a monad with zero and plus.  In Haskell 1.3 this type
and most operations are already in the prelude.
\begin{verbatim}
 data Maybe a = Nothing  | Just a deriving Show
 maybe :: b -> (a -> b) -> Maybe a -> b 

> unJust :: Maybe a -> a

\end{verbatim}
\subsection{Debugging}
For debugging \verb|trace| can be very useful - it prints its first
string argument as a side effect when it is reduced. It is the identity
function on its second argument. \verb|debug| shows it's argument and
returns it.

In H1.3 (hbc) we include the trace function from the module NonStdTrace.
\begin{verbatim}

> debug :: Show a => a -> a
> maytrace :: String -> a -> a


> maytrace _ = id -- debug info off


\end{verbatim}
\subsection{Pairs}
\begin{verbatim}

> mapFst :: (a -> b) -> (a, c) -> (b, c)
> mapSnd :: (a -> b) -> (c, a) -> (c, b)
> pair   :: a -> b -> (a,b)
> swap   :: (a, b) -> (b, a)

\end{verbatim}
\subsection{Misc.}
\begin{verbatim}

> variablename :: Int -> String

\end{verbatim}
\section{Implementation}
\begin{verbatim}

> flatMap f = concat . map f

> xs `without` ys = filter (\x -> not (elem x ys)) xs
> withoutBy eq xs ys = filter (\x -> not (myelem x ys)) xs
>     where myelem = any . eq

> splitUp preds []     = replicate (length preds + 1) []
> splitUp preds (x:xs) = let lists = splitUp preds xs 
>                        in try x preds lists
>   where try y []       [lastList]   = [(y:lastList)]
>         try y (pr:prs) (list:lists) 
>           | pr y      = (y:list) : lists
>           | otherwise = list:(try y prs lists)
>         try _ _  []      = error "MyPrelude.lhs: splitUp: impossible: too few lists"
>         try _ [] (_:_:_) = error "MyPrelude.lhs: splitUp: impossible: too many 
>lists"

> debug x = trace (show x) x
> maydebug :: Show a => a -> a
> maydebug x = maytrace (show x) x

> mapFst f (a,b) = (f a,b)
> mapSnd f (a,b) = (a,f b)

> pair x y = (x,y)
> swap (x,y) = (y,x)

> variablename n | n<26 = [num2chr n]
>   where num2chr m = toEnum (fromEnum 'a' + m)
> variablename n = variablename (n `div` 26 - 1) ++ 
>                  variablename (n `mod` 26) 

> unJust (Just x) = x
> unJust Nothing  = error "unJust!"

> unique xs = unique' xs [] 
> unique'  :: Eq a => [a] -> [a] -> [a]
> unique' [] = id
> unique' (x:xs) = (x:).(unique' [y|y<-xs,y/=x])

> combineUniqueBy eq = cu
>   where cu _  [] = []
>         cu qs (x:xs) | x `elemByeq` qs = cu qs xs
>                      | otherwise   = x:cu (x:qs) xs
>         elemByeq = any . eq

\end{verbatim}
> module Flags(Flags(..),flags) where
> import CommandLine(unsafeGetArgs,unsafeGetEnvDef)

> data Flags = Flags {verbose          :: Bool, 
>                     version          :: Bool, 
>                     help             :: Bool,
>                     requests         :: [String],
>                     preludeFileNames :: [String],
>                     fileargs         :: [String]}
>   deriving Show

> defaultPreludeFileName :: String


> defaultPreludeFileName = "/users/cs/patrikj/poly/polyp/PolyP/lib/PolyPrel.hs"


> preludeFileName :: String
> preludeFileName = unsafeGetEnvDef "POLYPPRELUDE" defaultPreludeFileName

> defaultflags :: Flags
> defaultflags = Flags {verbose          = False, 
>                       version          = False,
>                       help             = False,
>                       requests         = [],
>                       preludeFileNames = [preludeFileName],
>                       fileargs         = []}

> flags :: Flags
> flags = analyseFlags unsafeGetArgs

> analyseFlags :: [String] -> Flags
> analyseFlags []            = defaultflags
> analyseFlags (fl:rest)     
>    | isVersionFlag fl      = (analyseFlags rest) {version = True}         
>    | isVerboseFlag fl      = (analyseFlags rest) {verbose = True}         
>    | isHelpFlag fl         = (analyseFlags rest) {help    = True}         
> analyseFlags (fl:name:rest) 
>    | isIncludeFlag fl      = mapPrFileName (name:) (analyseFlags rest)
>    | isRequestFlag fl      = mapRequests    (name:) (analyseFlags rest)
> analyseFlags (file:rest)   = mapFileArgs   (file:) (analyseFlags rest)

> mapPrFileName :: ([String] -> [String]) -> Flags -> Flags
> mapPrFileName f x = x {preludeFileNames = f (preludeFileNames x)}

> mapRequests :: ([String] -> [String]) -> Flags -> Flags
> mapRequests f x = x {requests = f (requests x)}

> mapFileArgs :: ([String] -> [String]) -> Flags -> Flags
> mapFileArgs f x = x {fileargs = f (fileargs x)}

> isIncludeFlag :: String -> Bool
> isIncludeFlag = ("-p"==)

> isVerboseFlag :: String -> Bool
> isVerboseFlag = ("-v"==)

> isVersionFlag :: String -> Bool
> isVersionFlag = ("--version"==)

> isRequestFlag :: String -> Bool
> isRequestFlag = ("-r"==)

> isHelpFlag :: String -> Bool
> isHelpFlag ('-':c:_) = c `elem` "h?"
> isHelpFlag _         = False
Command Line arguments transformed to global variables.

> module CommandLine where
> import NonStdTrace(unsafePerformIO)
> import System(getEnv,getArgs)

> unsafeGetArgs :: [String]
> unsafeGetArgs = unsafePerformIO getArgs

> unsafeGetEnvDef :: String -> String -> String
> unsafeGetEnvDef e def = unsafePerformIO (getEnvDef e def)

> getEnvDef :: String -> String -> IO String
> getEnvDef e def = getEnv e `catch` \ _ -> return def

 maybeGetEnv :: String -> IO (Maybe String)
 maybeGetEnv e = (getEnv e <@ Just) `catch` \ _ -> return Nothing

Reply via email to