   else
     malformed op, 'Should use a type constructor here'
 
-typeConstraintCompile = (expression) ->
+typeConstraintCompile = (ctx, expression) ->
   op = _operator expression
   args = _arguments expression
   if isCall expression
     if isAtom op
       op.label = 'operator'
-      new ClassContraint op.symbol, typeCompile args[0] # TODO: support multiparameter type classes
+      new ClassContraint op.symbol, (typeCompile ctx, args[0]) # TODO: support multiparameter type classes
     else
       malformed expression, 'Class name required in a constraint'
   else
     malformed expression, 'Class constraint expected'
 
-typeConstraintsCompile = (expressions) ->
+typeConstraintsCompile = (ctx, expressions) ->
   filter ((t) -> t instanceof ClassContraint),
-    (map typeConstraintCompile, expressions)
-
-typeTupleCompile = (form) ->
+    (typeConstraintCompile ctx, e for e in expressions)
+
+typeTupleCompile = (ctx, form) ->
   form.label = 'operator'
   elemTypes = _terms form
-  applyKindFn (tupleType elemTypes.length), (typesCompile elemTypes)...
-
-typeConstantCompile = (atom) ->
+  applyKindFn (tupleType elemTypes.length), (typesCompile ctx, elemTypes)...
+
+typeConstantCompile = (ctx, atom) ->
   atom.label = 'typename'
-  atomicType atom.symbol, star
+  kind =
+    if isCapital atom
+      ctx.kindOfTypeName atom.symbol
+    else
+      star
+  throw new Error "type name #{atom.symbol} was not defined" unless kind
+  atomicType atom.symbol, kind
 
 # Inside definition, we call assignCompile with its RHS
 #   whether to call it and with what expression is left to the RHS expression


class Context
  constructor: ->
    @_macros = builtInMacros
    @expand = {}
    @definitions = []
    @_isOperator = []

binaryMathOpType = '(Fn Num Num Num)'
comparatorOpType = '(Fn a a Bool)'

builtInTypeNames = ->
  arrayToMap map (({name, kind}) -> [name, kind]), [
    arrowType
    listType
    hashmapType
    hashsetType
    stringType
    boolType
    numType
  ]

builtInContext = ->
  newMapWith 'True', (type: (quantifyAll toConstrained boolType), arity: []),
      'False', (type: (quantifyAll toConstrained boolType), arity: [])
      '==', (
        type: (quantifyAll toConstrained (typeFn (atomicType 'a', star), (atomicType 'a', star), boolType)),
        arity: ['x', 'y'])
  # concatMaps (mapMap desiplifyTypeAndArity, newMapWith '&', '(Fn a b b)', # TODO: replace with actual type
  #   'show-list', '(Fn a b)' # TODO: replace with actual type
  #   'from-nullable', '(Fn a b)' # TODO: replace with actual type JS -> Maybe a

  # TODO match

  # 'if', '(Fn Bool a a a)'
  # TODO JS interop

  # 'sqrt', '(Fn Num Num)'
  # 'not', '(Fn Bool Bool)'

  # '^', binaryMathOpType

  # '~', '(Fn Num Num)'

  # '+', binaryMathOpType
  # '*', binaryMathOpType
  # '==', comparatorOpType
  # '!=', comparatorOpType
  # 'and', '(Fn Bool Bool Bool)'
  # 'or', '(Fn Bool Bool Bool)'

  # '-', binaryMathOpType
  # '/', binaryMathOpType
  # 'rem', binaryMathOpType
  # '<', comparatorOpType
  # '>', comparatorOpType
  # '<=', comparatorOpType
  # '>=', comparatorOpType
  # ),
  # newMapWith 'True', (type: boolType, arity: [])
  #   'False', (type: boolType, arity: [])
  #   'empty-array', (type: (parseUnConstrainedType '(Fn (Array a))'), arity: [])
  #   'cons-array', (type: (parseUnConstrainedType '(Fn a (Array a) (Array a))'), arity: ['what', 'onto'])

desiplifyTypeAndArity = (simple) ->
  type = parseUnConstrainedType simple
