 
 prettyPrintWith = (printer, type) ->
   if type.ForAll
-    prettyPrintWith printer, type.type
+    prettyPrintWith printer, forallToHumanReadable type
   else if type.Constrained
     if _notEmpty type.constraints
       (map printer, join [type.type], type.constraints).join ' '
     else
       printer type.type
 
-humanPrintType = (type) ->
+forallToHumanReadable = (type) ->
+  notConstrained = (type) ->
+    if type.Types and type.types.length > 1
+      mapMap (-> findFreeInList type.types[1...]), notConstrained type.types[0]
+    else if type.TypeVariable
+      newSetWith type.name
+    else if type.TypeApp
+      notConstrained type.op
+    else
+      newSet()
+  _name = ({name}) -> name
+  toDependent = (name, deps) -> {name, deps: map ((name) -> {name}), setToArray deps}
+  constrained = freshInstance (new Context), type
+  allVars = findFree constrained
+  constrainingVars = concatMaps (notConstrained c.types for c in constrained.constraints)...
+  constrainingGroups = topologicallySortedGroups mapToArrayVia toDependent, constrainingVars
+  # constrainingVars.sort if a.name > b.name then 1 else if a.name < b.name then -1 else 0
+  [constraining, simple] = partitionMap ((_, name) -> inSet constrainingVars, name), allVars
   index = 0
-  nextName = ->
+  newVar = (name) -> new TypeVariable name, star
+  nextSimpleName = ->
     (String.fromCharCode 97 + index++ % 25)
-  safePrintType substitute (mapMap nextName, (findFree type)), type
+  sub = mapKeys (__ newVar, nextSimpleName), simple
+  nextConstrainingName = (name) ->
+    if name isnt 'undefined'
+      dependent = setToArray (lookupInMap constrainingVars, name)
+      nextSimpleName() + '-' +
+        (map ((name) -> (lookupInMap sub, name).name), dependent).join ''
+  for group in constrainingGroups
+    filtered = filterSet ((name) -> inSet constrainingVars, name), group
+    sub = concatMaps sub, (mapKeys (__ newVar, nextConstrainingName), filtered)
+  substitute sub, constrained
 
 printType = (type) ->
   if type.TypeVariable
-    "_#{type.name}"
+    if /^[0-9]/.test type.name
+      "_#{type.name}"
+    else
+      "#{type.name}"
   else if type.QuantifiedVar
     "#{type.var}"
   else if type.TypeConstr

    .replace(/\|/g, 'or_')
    .replace(/\?/g, 'p_')

deferredToGraph = (deferred) ->
  nodes = newMap()
  findOrAdd = (name) ->
    lookupOrAdd nodes, name, {name: name, edges: []}
  for {name, deps} in deferred
    node = findOrAdd name
    for dep in deps
      node.edges.push findOrAdd dep.name

# This function resolves the types of mutually recursive functions
resolveDeferredTypes = (ctx) ->
  if _notEmpty ctx.deferredBindings()
    groups = topologicallySortedGroups ctx.deferredBindings()
    for group in groups
      bindings = newMap()
      for binding in ctx.deferredBindings() when inSet group, binding.name
