 #     [x, xs...] = elems
 #     (call_ (token_ 'cons-array'), [x, (arrayToConses xs)])
 
+typeCompile = (ctx, expression) ->
+  throw new Error "invalid typeCompile args" unless ctx instanceof Context and expression
+  (if isAtom expression
+    typeConstantCompile
+  else if isTuple expression
+    typeTupleCompile
+  else if isCall expression
+    typeConstructorCompile
+  else
+    malformed expression, 'not a valid type'
+  )? ctx, expression
+
+typesCompile = (ctx, expressions) ->
+  map ((e) -> typeCompile ctx, e), expressions
+
+typeConstructorCompile = (ctx, call) ->
+  op = _operator call
+  args = _arguments call
+
+  if isAtom op
+    op.label = 'operator'
+    name = op.symbol
+    if name is 'Fn'
+      typeFn typesCompile ctx, args
+    else
+      arity = args.length
+      applyKindFn (new TypeConstr "[#{arity}]", kindFn arity), typesCompile ctx, args
+  else
+    malformed op, 'Should use a type constructor here'
+
+typeTupleCompile = (ctx, form) ->
+  form.label = 'operator'
+  elemTypes = _terms form
+  applyKindFn (tupleType elemTypes.length), typesCompile ctx, elemTypes
+
+typeConstantCompile = (ctx, atom) ->
+  name = atom.symbol
+  if /^[A-Z]/.test name
+    typeConstant name
+  else
+    new TypeVariable name, star
 
 # Inside definition, we call assignCompile with its RHS
 #   whether to call it and with what expression is left to the RHS expression

        [type, body, wheres...] = defs
      else
        [body, wheres...] = defs
      paramNames = map _symbol, params
      # pattern
      paramTypes = map (-> toForAll ctx.freshTypeVariable star), params

  isAtDefinition: ->
    (definition = @_currentDefinition()) and definition.inside is 0

  isAtSimpleDefinition: ->
    @isAtDefinition() and @definitionName()

  # isInsideDefinition: ->
  #   (definition = @_currentDefinition()) and definition.inside isnt 0

