This might not be considered a real bug, bug I suspect a lot of users will
find it annoying. When upgrading hugs to hugs98 (May 1999) I get the
following message when using hugs to run PolyP:
  ERROR "Grammar.lhs" (line 42): 
  *** Cannot derive Eq (Eqn' a) after 40 iterations.
  *** This may indicate that the problem is undecidable.  However,
  *** you may still try to increase the cutoff limit using the -c
  *** option and then try again.  (The current setting is -c40)

It turns out that I need to set roughly -c70 to get this file through. I
never needed this with the old hugs. I don't think the datatype is _that_
complicated so I suggest that the default is changed upwards to some
substantially higher number to make this error very unlikely. (Or change
the counting procedure.)

I include the source of this module to show the size of the datatype Eqn',
but it can't be compiled without a number of other modules. If you really
want to try to compile it, the sources can be downloaded from 

  www.cs.chalmers.se/~patrikj/poly/polyp/

Patrik Jansson, Chalmers
\chapter{PolyP's Grammar}
\begin{verbatim}

> module Grammar where
> import MyPrelude(mapSnd)

> infixl 9 :@:
> infixl 9 :@@:
> infixr 9 -=>
> infix  4 :=>

\end{verbatim}
\section{Equations}
There are seven kinds of equations:
\begin{itemize}
\item Variable bindings (\verb|VarBind|) can appear both at top-level
  and in a \verb|let|-construct. They bind a variable to a body (which
  is an expression).
\item Polytypic variable bindings.
\item Data type definitions (\verb|DataDef|) can only appear at
  top-level. A data definition defines a new type and a set of
  functions (constructors) that build values of this new type.
\item Explicitly typed variables.
\item Type synonym declarations.
\item Class declarations.
\item Instance declarations.
\end{itemize}
(Currently, the three last constructs are not parsed, nor handled in
the type inference algorithm)

The datatype \verb|Eqn'| is mutually recursive with the type for
expressions as the expressions in the variable bindings can contain
let-expressions which in turn contains equations. The type parameter
\verb|t| is used in \verb|Expr'| to denote the type of types as there
will be a need for different representation for types later. The {\tt
  Maybe} in {\tt VarBind} is used for a possible explicit type.
(Dependency analysis will combine {\tt ExplType} with the
corresponding {\tt VarBind}s.
\begin{verbatim}

> data Eqn' t
>    = VarBind VarID (Maybe t) [Pat' t] (Expr' t)
>    | Polytypic VarID t t [(t, Expr' t)]
>    | DataDef ConID [VarID] [(ConID, [Type])]   [ConID]
>    | ExplType [VarID] t

>    | TypeSyn ConID [VarID] Type
>    | Class    [Context] Context [Eqn' t] 
>    | Instance [Context] Context [Eqn' t]

>    deriving Eq

> type Func = Type

\end{verbatim}
(It is not completely clear yet if \verb|t| should be used in more
places.)

A future enhancement would be to extend the \verb|VarBind| to
\verb|PatBind| that just takes a pattern and an expression thus
allowing definitions like {\tt (a,b) = f 3} where f is a function
returning a pair.

Only VarBind and ExplType are allowed in letrecs.
\section{Expressions, patterns, types and kinds}
Expressions are similar to patterns and types are similar to kinds in
many ways.  So we use one data type for each pair. An advantage is
that a lot of code can be shared (e.g. \verb|fold|). A problem with
this approach is that the pairs are not completely the same. Patterns
can use everything but $\lambda$-abstractions, \verb|case| and
\verb|letrec| expressions.  Finally, expressions can't use the
\verb|WildCard| constructor (maybe in expressions \verb|WildCard|
could denote \verb|undefined|).  (Patterns are combinations of
variables, constants, applications, literals and wildcards. )
\begin{verbatim}

> data Expr' t
>    = Var VarID 
>    | Con ConID 
>    | (Expr' t) :@: (Expr' t)
>    | Lambda (Pat' t) (Expr' t)
>    | Literal Literal
>    | WildCard
>    | Case (Expr' t) [(Pat' t, Expr' t)]
>    | Letrec [[Eqn' t]] (Expr' t)
>    | Typed (Expr' t) t

>    deriving Eq

> type Pat' t = Expr' t

> data Type
>    = TVar VarID
>    | TCon ConID
>    | Type :@@: Type    
>    deriving (Eq)

> type Kind = Type

\end{verbatim}
Normally (that is, everywhere except during type inference)
expressions, patterns and equations use the type \verb|QType| to
represent the types. A program consists of a list of datatype
definitions followed by a list (ordered by dependencies) of blocks of
mutually recursive definitions.
\begin{verbatim}

> type Expr    = Expr' QType
> type Pat     = Pat'  QType
> type Eqn     = Eqn'  QType
> type PrgEqns = ([Eqn],[[Eqn]])

> data Qualified t = [Qualifier t] :=> t 
>                    deriving (Eq)
> deQualify :: Qualified t -> t
> qualify :: t -> Qualified t 

> noType :: Maybe QType
> noType = Nothing

> instance Functor Qualified where
>   fmap f (qs:=>t) = map (mapSnd (map f)) qs :=> f t

> context2type :: Context -> Type
> type Qualifier t = (ConID,[t])
> type Context = Qualifier Type

> type QType = Qualified Type

\end{verbatim}
Expressions labelled with types can be expressed with elements of
\verb|TExpr| where every second level is the \verb|Typed| constructor.
\begin{verbatim}

> type TExpr   = Expr' QType
> type TEqn    = Eqn'  QType
> type PrgTEqns = ([Eqn],[[TEqn]])

\end{verbatim}
\section{Literals}
Integers, floats, characters, booleans and strings supported so far.
\begin{verbatim}

> data Literal
>    = IntLit Int
>    | FloatLit Float
>    | BoolLit Bool
>    | CharLit Char
>    | StrLit String
>    deriving Eq

\end{verbatim}
\section{Miscellaneous types}
A later optimisation would be to parametrise the type of expressions
with the type of identifiers --- strings are not very efficient. As
soon as parsing has finished the strings could be replaced by integers
and a lookup table. A type parameter could be added to Expr' and Eqn'
and new maps ... written over that structure.
\begin{verbatim}

> type VarID = String
> type ConID = String

\end{verbatim}
\section{Access- and check-functions}
Function \verb|spineWalk|(-\verb|Type|) converts an expression (a
type) to a non-empty list containing the head of the application and
all arguments.
\begin{verbatim}

> spineWalk :: Expr' a -> [Expr' a]
> spineWalk e = sW e []
>   where sW (x :@: y) = sW x . (y:)
>         sW  x        = (x:)

> spineWalkType :: Type -> [Type]
> spineWalkType t = sW t []
>   where sW (x :@@: y) = sW x . (y:)
>         sW  x        = (x:)

> isVarBind :: Eqn' t -> Bool
> isVarBind (VarBind _ _ _ _) = True
> isVarBind _             = False

> isDataDef :: Eqn' t -> Bool
> isDataDef (DataDef _ _ _ _) = True
> isDataDef _               = False

> isExplType :: Eqn' t -> Bool
> isExplType (ExplType _ _) = True
> isExplType _              = False

> isPolytypic :: Eqn' t -> Bool
> isPolytypic (Polytypic _ _ _ _) = True
> isPolytypic _                   = False

> changeNameOfBind :: (String -> String) -> Eqn' t -> Eqn' t
> changeNameOfBind f (VarBind n t ps e) = VarBind (f n) t ps e
> changeNameOfBind f (Polytypic n t fun cs) = Polytypic (f n) t fun cs
> changeNameOfBind _ _ = error "Grammar.changeNameOfBind: neither VarBind nor 
>Polytypic"
> getNameOfEqn :: Eqn -> String
> getNameOfEqn (VarBind name _ _ _)   = name
> getNameOfEqn (Polytypic name _ _ _) = name
> getNameOfEqn (DataDef name _ _ _)   = name
> getNameOfEqn (ExplType names _)     = "{-Typed: "++head names++
>                                       if length names>1 then "..." else ""++
>                                       "-}"
> getNameOfEqn _                      = "{-Other-}"


> getNameOfBind :: Eqn' t -> String
> getNameOfBind (VarBind name _ _ _)     = name
> getNameOfBind (Polytypic name _ _ _) = name
> getNameOfBind _ = error "Grammar.getNameOfBind: wrong argument"

> getNameOfVarBind :: Eqn' t -> String
> getNameOfVarBind (VarBind name _ _ _)  = name
> getNameOfVarBind _ =error "Grammar.getNameOfVarBind: wrong argument"

> getNameOfDataDef :: Eqn' t -> String
> getNameOfDataDef (DataDef name _ _ _) = name
> getNameOfDataDef _ =error "Grammar.getNameOfDataDef: wrong argument"

> deQualify (_:=>t) = t
> qualify t = []:=>t

> functionConstructor :: ConID
> functionConstructor = "->"

> isFunctionType :: Type -> Bool
> isFunctionType (TCon c) =  c == functionConstructor
> isFunctionType _        =  False

> (-=>) :: Type -> Type -> Type 
> a -=> b = TCon functionConstructor :@@: a :@@: b

> listConstructor :: String
> listConstructor = "[]"

> tupleConstructor :: Int -> ConID
> tupleConstructor n = ( ('(':replicate (max (n-1) 0) ',')++")")

> isTupleCon :: ConID -> Bool
> isTupleCon (c:_) = c=='('
> isTupleCon []     = error "Grammar.isTupleCon: impossible: empty constructor"

> context2type (c,ts) = foldl (:@@:) (TCon c) ts

\end{verbatim}

Reply via email to