     @variableIndex = 0
     @typeVariabeIndex = 0
     @nameIndex = 1
-    @substitution = newMap()
+    @substitution = emptySubstitution()
     @statement = []
     @cacheScopes = [[]]
     @_assignTos = []

    s2 = matchType t1.arg, t2.arg
    s3 = mergeSubs s1, s2
    s3 or
      newMapWith "could not unify", [(safePrintType t1), (safePrintType t2)]
  else if t1 instanceof Types and t2 instanceof Types
    if _notEmpty t1.types
      s1 = matchType t1.types[0], t2.types[0]
      s2 = matchType (new Types t1.types[1...]), (new Types t2.types[1...])
      s3 = mergeSubs s1, s2
      s3 or
        newMapWith "could not unify", [(safePrintType t1), (safePrintType t2)]
    else
      emptySubstitution()
  else
    newMapWith "could not unify", [(safePrintType t1), (safePrintType t2)]

joinSubs = (s1,s2) ->
  concatMaps s1, mapMap ((type) -> substitute s1, type), s2

mergeSubs = (s1, s2) ->
  agree = (varName) ->
    variable = new TypeVariable varName, star
    typeEq (substitute s1, variable), (substitute s2, variable)
  if allMap agree, keysOfMap intersectRight s1, s2
    concatMaps s1, s2
  else
    null

emptySubstitution = ->
  newMap()

# Unlike in Jones, we simply use substitute for both variables and quantifieds
# - variables are strings, wheres quantifieds are ints
substitute = (substitution, type) ->
  if type instanceof TypeVariable and substitution.values
    (lookupInMap substitution, type.name) or type
  else if type instanceof QuantifiedVar
    substitution[type.var] or type
  else if type instanceof TypeApp


# Primitive type checking for now
checkTypes = (ctx) ->
  # failed = mapToArray filterMap ((name) -> name is 'could not unify'), ctx.substitution
  if _notEmpty (failed = ctx.substitution.fails)
    throw new Error failed[0]

lookupJs = (moduleName) ->
  js = (lookupInMap compiledModules, moduleName)?.js
