2
votes

I defined Symbol data type that can be either BuiltInTypeSymbol or ProcedureSymbol. ProcedureSymbol may have a parent of type Scope. So I added Scope type constraint for ProcedureSymbol data constructor and parent function.

data Symbol where 
     BuiltInTypeSymbol :: String -> Symbol
     ProcedureSymbol   :: Scope sc => String -> sc -> [Symbol] -> Symbol

name :: Symbol -> String
name (BuiltInTypeSymbol n) = n
name (ProcedureSymbol n _ _) = n 

parent :: Scope sc => Symbol -> Maybe sc
parent (ProcedureSymbol _ par _) = Just par
parent _ = Nothing

class Scope s where
    getName           :: s -> String
    getEnclosingScope :: Scope sc => s -> Maybe sc
    define            :: s -> Symbol -> s
    resolve           :: s -> String -> Maybe Symbol

When I try to compile this code I got the following compile error:

SymbolTable.hs:13:36: error:
    * Couldn't match type `sc1' with `sc'
      `sc1' is a rigid type variable bound by
        a pattern with constructor:
          ProcedureSymbol :: forall sc.
                             Scope sc =>
                             String -> sc -> [Symbol] -> Symbol,
        in an equation for `parent'
        at SymbolTable.hs:13:9
      `sc' is a rigid type variable bound by
        the type signature for:
          parent :: forall sc. Scope sc => Symbol -> Maybe sc
        at SymbolTable.hs:12:11
      Expected type: Maybe sc
        Actual type: Maybe sc1
    * In the expression: Just par
      In an equation for `parent':
          parent (ProcedureSymbol _ par _) = Just par
    * Relevant bindings include
        par :: sc1 (bound at SymbolTable.hs:13:27)
        parent :: Symbol -> Maybe sc (bound at SymbolTable.hs:13:1)

How can I make this code compile?

1
The definition of Symbol says that whoever creates a Symbol with ProcedureSymbol gets to pick the sy type. But the type of parent (which is the same as forall sc. Scope sc => Symbol -> Maybe sc) says that whoever calls parent gets to pick the type. You could have a type argument for the Symbol type that tells you what the sc type is.David Young

1 Answers

1
votes

As @David Young pointed, you can add a type parameter to your Symbol constructor, like this:

{-# LANGUAGE GADTs #-}

data Symbol a where
     BuiltInTypeSymbol :: String -> Symbol a
     ProcedureSymbol   :: Scope a => String -> a -> [Symbol a] -> Symbol a

class Scope s where
    getName           :: s -> String
    getEnclosingScope :: Scope sc => s -> Maybe sc
    define            :: s -> Symbol s-> s
    resolve           :: s -> String -> Maybe (Symbol s)

name :: Symbol a -> String
name (BuiltInTypeSymbol n) = n
name (ProcedureSymbol n _ _) = n 

parent :: Scope sc => Symbol sc -> Maybe sc
parent (ProcedureSymbol _ par _) = Just par
parent _ = Nothing