diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012-2014, Evan Czaplicki
+Copyright (c) 2012-2015, Evan Czaplicki
 
 All rights reserved.
 
diff --git a/elm-compiler.cabal b/elm-compiler.cabal
--- a/elm-compiler.cabal
+++ b/elm-compiler.cabal
@@ -1,6 +1,6 @@
 
 Name: elm-compiler
-Version: 0.14
+Version: 0.14.1
 
 Synopsis:
     Values to help with elm-package, elm-make, and elm-lang.org.
@@ -27,9 +27,6 @@
 Cabal-version: >=1.9
 Build-type: Simple
 
-Data-files:
-    runtime/debug.js
-
 source-repository head
     type:     git
     location: git://github.com/elm-lang/elm-compiler.git
@@ -98,6 +95,7 @@
         Type.Environment,
         Type.ExtraChecks,
         Type.Fragment,
+        Type.Hint,
         Type.Inference,
         Type.PrettyPrint,
         Type.Solve,
diff --git a/runtime/debug.js b/runtime/debug.js
deleted file mode 100644
--- a/runtime/debug.js
+++ /dev/null
@@ -1,604 +0,0 @@
-(function() {
-'use strict';
-
-if (typeof window != 'undefined' && !window.location.origin) {
-  window.location.origin =
-      window.location.protocol + "//" +
-      window.location.hostname +
-      (window.location.port ? (':' + window.location.port) : '');
-}
-
-Elm.fullscreenDebugHooks = function(elmModule, debuggerHistory /* =undefined */) {
-  var exposedDebugger = {};
-  function debuggerAttach(elmModule, debuggerHistory) {
-    return {
-      make: function(runtime) {
-        var wrappedModule = debugModule(elmModule, runtime);
-        exposedDebugger = debuggerInit(wrappedModule, runtime, debuggerHistory);
-        return wrappedModule.debuggedModule;
-      }
-    }
-  }
-  var mainHandle = Elm.fullscreen(debuggerAttach(elmModule, debuggerHistory));
-  mainHandle.debugger = exposedDebugger;
-  return mainHandle;
-};
-
-var EVENTS_PER_SAVE = 100;
-
-function debugModule(module, runtime) {
-  var programPaused = false;
-  var recordedEvents = [];
-  var asyncCallbacks = [];
-  var snapshots = [];
-  var watchTracker = Elm.Native.Debug.make(runtime).watchTracker;
-  var pauseTime = 0;
-  var eventsUntilSnapshot = EVENTS_PER_SAVE;
-  runtime.debuggerStatus = runtime.debuggerStatus || {};
-  runtime.debuggerStatus.eventCounter = runtime.debuggerStatus.eventCounter || 0;
-
-  // runtime is the prototype of wrappedRuntime
-  // so we can access all runtime properties too
-  var wrappedRuntime = Object.create(runtime);
-  wrappedRuntime.notify = notifyWrapper;
-  wrappedRuntime.setTimeout = setTimeoutWrapper;
-
-  // make a copy of the wrappedRuntime
-  var assignedPropTracker = Object.create(wrappedRuntime);
-  var debuggedModule = module.make(assignedPropTracker);
-
-  // make sure the signal graph is actually a signal & extract the visual model
-  if ( !('recv' in debuggedModule.main) ) {
-    debuggedModule.main = Elm.Signal.make(runtime).constant(debuggedModule.main);
-  }
-
-  // The main module stores imported modules onto the runtime.
-  // To ensure only one instance of each module is created,
-  // we assign them back on the original runtime object.
-  Object.keys(assignedPropTracker).forEach(function(key) {
-    runtime[key] = assignedPropTracker[key];
-  });
-
-  var signalGraphNodes = flattenSignalGraph(wrappedRuntime.inputs);
-  var tracePath = tracePathInit(runtime, debuggedModule.main);
-
-  snapshots.push(snapshotSignalGraph(signalGraphNodes));
-
-  function notifyWrapper(id, v) {
-    var timestep = runtime.timer.now();
-
-    if (programPaused) {
-      // ignore async events generated while playing back
-      // or user events while program is paused
-      return false;
-    }
-    else {
-      recordEvent(id, v, timestep);
-      var changed = runtime.notify(id, v, timestep);
-      snapshotOnCheckpoint();
-      if (parent.window) {
-        parent.window.postMessage("elmNotify", window.location.origin);
-      }
-      return changed;
-    }
-  };
-
-  function setTimeoutWrapper(func, delayMs) {
-    if (programPaused) {
-      // Don't push timers and such to the callback stack while we're paused.
-      // It causes too many callbacks to be fired during unpausing.
-      return 0;
-    }
-    var cbObj = { func:func, delayMs:delayMs, timerId:0, executed:false };
-    var timerId = setTimeout(function() {
-        cbObj.executed = true;
-        func();
-      }, delayMs);
-    cbObj.timerId = timerId;
-    asyncCallbacks.push(cbObj);
-    return timerId;
-  }
-
-  function recordEvent(id, v, timestep) {
-    watchTracker.pushFrame();
-    recordedEvents.push({ id:id, value:v, timestep:timestep });
-    runtime.debuggerStatus.eventCounter += 1;
-  }
-
-  function clearAsyncCallbacks() {
-    asyncCallbacks.forEach(function(timer) {
-      if (!timer.executed) {
-        clearTimeout(timer.timerId);
-      }
-    });
-  }
-
-  function clearRecordedEvents() {
-    recordedEvents = [];
-    runtime.debuggerStatus.eventCounter = 0;
-  }
-
-  function getRecordedEventsLength() {
-    return recordedEvents.length;
-  }
-
-  function getRecordedEventAt(i) {
-    return recordedEvents[i];
-  }
-
-  function copyRecordedEvents() {
-    return recordedEvents.slice();
-  }
-
-  function loadRecordedEvents(events) {
-    recordedEvents = events.slice();
-  }
-
-  function clearSnapshots() {
-    snapshots = [snapshotSignalGraph(signalGraphNodes)];
-  }
-
-  function getSnapshotAt(i) {
-    var snapshotEvent = Math.floor(i / EVENTS_PER_SAVE);
-    assert(snapshotEvent < snapshots.length && snapshotEvent >= 0,
-           "Out of bounds index: " + snapshotEvent);
-    return snapshots[snapshotEvent];
-  }
-
-  function snapshotOnCheckpoint() {
-    if (eventsUntilSnapshot === 1) {
-      snapshots.push(snapshotSignalGraph(signalGraphNodes));
-      eventsUntilSnapshot = EVENTS_PER_SAVE;
-    } else {
-      eventsUntilSnapshot -= 1;
-    }
-  }
-
-  function setPaused() {
-    programPaused = true;
-    clearAsyncCallbacks();
-    pauseTime = Date.now();
-    tracePath.stopRecording();
-    preventInputEvents();
-  }
-
-  function setContinue(position) {
-    var pauseDelay = Date.now() - pauseTime;
-    runtime.timer.addDelay(pauseDelay);
-    programPaused = false;
-
-    // we need to dump the events that are ahead of where we're continuing.
-    var lastSnapshotPosition = Math.floor(position / EVENTS_PER_SAVE);
-    eventsUntilSnapshot = EVENTS_PER_SAVE - (position % EVENTS_PER_SAVE);
-    snapshots = snapshots.slice(0, lastSnapshotPosition + 1);
-
-    if (position < getRecordedEventsLength()) {
-      var lastEventTime = recordedEvents[position].timestep;
-      var scrubTime = runtime.timer.now() - lastEventTime;
-      runtime.timer.addDelay(scrubTime);
-    }
-
-    recordedEvents = recordedEvents.slice(0, position);
-    tracePath.clearTracesAfter(position);
-    runtime.debuggerStatus.eventCounter = position;
-    executeCallbacks(asyncCallbacks);
-    permitInputEvents();
-
-    tracePath.startRecording();
-  }
-
-  function getPaused() {
-    return programPaused;
-  }
-
-  function preventInputEvents(){
-    var events =
-      [ "click", "mousemove", "mouseup", "mousedown", "mouseclick"
-      , "keydown", "keypress", "keyup", "touchstart", "touchend"
-      , "touchcancel", "touchleave", "touchmove", "pointermove"
-      , "pointerdown", "pointerup", "pointerover", "pointerout"
-      , "pointerenter", "pointerleave", "pointercancel"
-      ];
-
-    var ignore = function(e) {
-      var evt = e ? e : window.event;
-      if (evt.stopPropagation) {
-        evt.stopPropagation();
-      }
-      if (evt.cancelBubble !== null) {
-        evt.cancelBubble = true;
-      }
-      if (evt.preventDefault) {
-        evt.preventDefault();
-      }
-      return false;
-    };
-
-    var ignoringDiv = document.getElementById("elmEventIgnorer");
-    if (!ignoringDiv) {
-      ignoringDiv = document.createElement("div");
-      ignoringDiv.id = "elmEventIgnorer";
-      ignoringDiv.style.position = "absolute";
-      ignoringDiv.style.top = "0px";
-      ignoringDiv.style.left = "0px";
-      ignoringDiv.style.width = "100%";
-      ignoringDiv.style.height = "100%";
-
-      for (var i = events.length; i-- ;) {
-        ignoringDiv.addEventListener(events[i], ignore, true);
-      }
-      runtime.node.appendChild(ignoringDiv);
-    }
-  }
-
-  function permitInputEvents(){
-    var ignoringDiv = document.getElementById("elmEventIgnorer");
-    ignoringDiv.parentNode.removeChild(ignoringDiv);
-  }
-
-  return {
-    debuggedModule: debuggedModule,
-    signalGraphNodes: signalGraphNodes,
-    initialSnapshot: snapshotSignalGraph(signalGraphNodes),
-    initialAsyncCallbacks: asyncCallbacks.slice(),
-    // API functions
-    clearAsyncCallbacks: clearAsyncCallbacks,
-    clearRecordedEvents: clearRecordedEvents,
-    getRecordedEventsLength: getRecordedEventsLength,
-    getRecordedEventAt: getRecordedEventAt,
-    copyRecordedEvents: copyRecordedEvents,
-    loadRecordedEvents: loadRecordedEvents,
-    clearSnapshots: clearSnapshots,
-    getSnapshotAt: getSnapshotAt,
-    snapshotOnCheckpoint: snapshotOnCheckpoint,
-    getPaused: getPaused,
-    setPaused: setPaused,
-    setContinue: setContinue,
-    tracePath: tracePath,
-    watchTracker: watchTracker
-  };
-}
-
-// The debuggerHistory variable is passed in on swap. It represents
-// the a state of the debugger for it to assume during init. It contains
-// the paused state of the debugger, the recorded events, and the current
-// event being processed.
-function debuggerInit(debugModule, runtime, debuggerHistory /* =undefined */) {
-  var currentEventIndex = 0;
-
-  function resetProgram(position) {
-    var closestSnapshot = debugModule.getSnapshotAt(position);
-    debugModule.clearAsyncCallbacks();
-    restoreSnapshot(debugModule.signalGraphNodes, closestSnapshot);
-    redrawGraphics();
-  }
-
-  function restartProgram() {
-    pauseProgram();
-    resetProgram(0);
-    debugModule.watchTracker.clear();
-    debugModule.tracePath.clearTraces();
-    debugModule.setContinue(0);
-    debugModule.clearRecordedEvents();
-    debugModule.clearSnapshots();
-    executeCallbacks(debugModule.initialAsyncCallbacks);
-  }
-
-  function pauseProgram() {
-    debugModule.setPaused();
-    currentEventIndex = debugModule.getRecordedEventsLength();
-  }
-
-  function continueProgram() {
-    if (debugModule.getPaused())
-    {
-      var closestSnapshotIndex =
-          Math.floor(currentEventIndex / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
-      resetProgram(currentEventIndex);
-      var continueIndex = currentEventIndex;
-      currentEventIndex = closestSnapshotIndex;
-      stepTo(continueIndex);
-      debugModule.setContinue(currentEventIndex);
-    }
-  }
-
-  function stepTo(index) {
-    if (!debugModule.getPaused()) {
-      debugModule.setPaused();
-      resetProgram();
-    }
-
-    if (index < 0 || index > getMaxSteps()) {
-      throw "Index out of bounds: " + index;
-    }
-
-    if (index < currentEventIndex) {
-      var closestSnapshotIndex = Math.floor(index / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
-      resetProgram(index);
-      currentEventIndex = closestSnapshotIndex;
-    }
-
-    while (currentEventIndex < index) {
-      var nextEvent = debugModule.getRecordedEventAt(currentEventIndex);
-      runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);
-
-      currentEventIndex += 1;
-    }
-  }
-
-  function getMaxSteps() {
-    return debugModule.getRecordedEventsLength();
-  }
-
-  function redrawGraphics() {
-    var main = debugModule.debuggedModule.main
-    for (var i = main.kids.length ; i-- ; ) {
-      main.kids[i].recv(runtime.timer.now(), true, main.id);
-    }
-  }
-
-  function getSwapState() {
-    var continueIndex = currentEventIndex;
-    if (!debugModule.getPaused()) {
-      continueIndex = getMaxSteps();
-    }
-    return {
-      paused: debugModule.getPaused(),
-      recordedEvents: debugModule.copyRecordedEvents(),
-      currentEventIndex: continueIndex
-    };
-  }
-
-  function dispose() {
-    var parentNode = runtime.node.parentNode;
-    parentNode.removeChild(debugModule.tracePath.canvas);
-    parentNode.removeChild(runtime.node);
-  }
-
-  if (debuggerHistory) {
-    // The problem is that we want to previous paused state. But
-    // by the time JS reaches here, the old code has been swapped out
-    // and the new modules are being generated. So we can ask the
-    // debugging console what it thinks the pause state is and go
-    // from there.
-    var paused = debuggerHistory.paused;
-    debugModule.setPaused();
-    debugModule.loadRecordedEvents(debuggerHistory.recordedEvents);
-    var index = getMaxSteps();
-    runtime.debuggerStatus.eventCounter = 0;
-    debugModule.tracePath.clearTraces();
-
-    // draw new trace path
-    debugModule.tracePath.startRecording();
-    while(currentEventIndex < index) {
-      var nextEvent = debugModule.getRecordedEventAt(currentEventIndex);
-      runtime.debuggerStatus.eventCounter += 1;
-      runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);
-      debugModule.snapshotOnCheckpoint();
-      currentEventIndex += 1;
-    }
-    debugModule.tracePath.stopRecording();
-
-    stepTo(debuggerHistory.currentEventIndex);
-    if (!paused) {
-      debugModule.setContinue(debuggerHistory.currentEventIndex);
-    }
-  }
-
-  runtime.node.parentNode.appendChild(debugModule.tracePath.canvas);
-
-  var elmDebugger = {
-      restart: restartProgram,
-      pause: pauseProgram,
-      kontinue: continueProgram,
-      getMaxSteps: getMaxSteps,
-      stepTo: stepTo,
-      getPaused: debugModule.getPaused,
-      getSwapState: getSwapState,
-      dispose: dispose,
-      allNodes: debugModule.signalGraphNodes,
-      watchTracker: debugModule.watchTracker
-  };
-
-  return elmDebugger;
-}
-
-function Point(x, y) {
-  this.x = x;
-  this.y = y;
-
-  this.translate = function(x, y) {
-    return new Point(this.x + x, this.y + y);
-  }
-
-  this.equals = function(p) {
-    return this.x == p.x && this.y == p.y;
-  }
-}
-
-function tracePathInit(runtime, signalGraphMain) {
-  var List = Elm.List.make(runtime);
-  var Signal = Elm.Signal.make(runtime);
-  var tracePathNode = A2(Signal.map, graphicsUpdate, signalGraphMain);
-  var tracePathCanvas = createCanvas();
-  var tracePositions = {};
-  var recordingTraces = true;
-
-  function findPositions(currentScene) {
-    var positions = {};
-    function processElement(elem, offset) {
-      if (elem.element.ctor == "Custom" && elem.element.type == "Collage")
-      {
-        List.map(F2(processForm)(offset))(elem.element.model.forms);
-      }
-    }
-
-    function processForm(offset, form) {
-      if (form.form.ctor == "FElement")
-      {
-        processElement(form.form._0, offset.translate(form.x, -form.y));
-      }
-      if (form.form.ctor == "FGroup")
-      {
-        var newOffset = offset.translate(form.x, -form.y);
-        List.map(F2(processForm)(newOffset))(form.form._1);
-      }
-      if (form.debugTracePathId)
-      {
-        positions[form.debugTracePathId] = new Point(form.x + offset.x, -form.y + offset.y);
-      }
-    }
-
-    processElement(currentScene, new Point(0, 0));
-    return positions;
-  }
-
-  function appendPositions(positions) {
-    for (var id in positions) {
-      var pos = positions[id];
-      if (tracePositions.hasOwnProperty(id)) {
-        tracePositions[id].push(pos);
-      }
-      else {
-        tracePositions[id] = [pos];
-      }
-      if (tracePositions[id].length < runtime.debuggerStatus.eventCounter) {
-        var padCount = runtime.debuggerStatus.eventCounter - tracePositions[id].length;
-        var lastTracePosition = tracePositions[id][tracePositions[id].length - 1];
-        for (var i = padCount; i--;) {
-          tracePositions[id].push(lastTracePosition)
-        }
-      }
-      assert(tracePositions[id].length === runtime.debuggerStatus.eventCounter,
-             "We don't have a 1-1 mapping of trace positions to events");
-    }
-  }
-
-  function graphicsUpdate(currentScene) {
-    if (!recordingTraces) {
-      return;
-    }
-
-    var ctx = tracePathCanvas.getContext('2d');
-    ctx.clearRect(0, 0, tracePathCanvas.width, tracePathCanvas.height);
-
-    ctx.save();
-    ctx.translate(ctx.canvas.width/2, ctx.canvas.height/2);
-    appendPositions(findPositions(currentScene));
-    for (var id in tracePositions)
-    {
-      ctx.beginPath();
-      var points = tracePositions[id];
-      for (var i=0; i < points.length; i++)
-      {
-        var p = points[i];
-        if (i == 0) {
-          ctx.moveTo(p.x, p.y);
-        }
-        else {
-          ctx.lineTo(p.x, p.y);
-        }
-      }
-      ctx.lineWidth = 1;
-      ctx.strokeStyle = "rgba(50, 50, 50, 0.4)";
-      ctx.stroke();
-    }
-
-    ctx.restore();
-  }
-
-  function clearTraces() {
-    tracePositions = {};
-  }
-
-  function stopRecording() {
-    recordingTraces = false;
-  }
-
-  function startRecording() {
-    recordingTraces = true;
-  }
-
-  function clearTracesAfter(position) {
-    var newTraces = {};
-    for (var id in tracePositions) {
-      newTraces[id] = tracePositions[id].slice(0,position);
-    }
-    tracePositions = newTraces;
-  }
-
-  return {
-    graphicsUpdate: graphicsUpdate,
-    canvas: tracePathCanvas,
-    clearTraces: clearTraces,
-    clearTracesAfter: clearTracesAfter,
-    stopRecording: stopRecording,
-    startRecording: startRecording
-  }
-}
-
-function executeCallbacks(callbacks) {
-  callbacks.forEach(function(timer) {
-    if (!timer.executed) {
-      var func = timer.func;
-      timer.executed = true;
-      func();
-    }
-  });
-}
-
-function createCanvas() {
-  var c = document.createElement('canvas');
-  c.width = window.innerWidth;
-  c.height = window.innerHeight;
-  c.style.position = "absolute";
-  c.style.top = "0";
-  c.style.left = "0";
-  c.style.pointerEvents = "none";
-  return c;
-}
-
-function assert(bool, msg) {
-  if (!bool) {
-    throw "Assertion error: " + msg;
-  }
-}
-
-function snapshotSignalGraph(signalGraphNodes) {
-  var nodeValues = [];
-
-  signalGraphNodes.forEach(function(node) {
-    nodeValues.push({ value: node.value, id: node.id });
-  });
-
-  return nodeValues;
-};
-
-function restoreSnapshot(signalGraphNodes, snapshot) {
-  assert(signalGraphNodes.length == snapshot.length,
-         "saved program state has wrong length");
-  for (var i=0; i < signalGraphNodes.length; i++) {
-    var node = signalGraphNodes[i];
-    var state = snapshot[i];
-    assert(node.id == state.id, "the nodes moved position");
-
-    node.value = state.value;
-  }
-}
-
-function flattenSignalGraph(nodes) {
-  var nodesById = {};
-
-  function addAllToDict(node) {
-    nodesById[node.id] = node;
-    node.kids.forEach(addAllToDict);
-  }
-  nodes.forEach(addAllToDict);
-
-  var allNodes = Object.keys(nodesById).sort().map(function(key) {
-    return nodesById[key];
-  });
-  return allNodes;
-};
-
-}());
diff --git a/src/AST/Annotation.hs b/src/AST/Annotation.hs
--- a/src/AST/Annotation.hs
+++ b/src/AST/Annotation.hs
@@ -4,59 +4,97 @@
 import qualified Text.PrettyPrint as P
 import AST.PrettyPrint
 
-data Annotated annotation expr = A annotation expr
+
+data Annotated annotation expr
+    = A annotation expr
     deriving (Show)
 
+
 data Region
     = Span Position Position P.Doc
     | None P.Doc
     deriving (Show)
 
+
 data Position = Position
     { line :: Int
     , column :: Int
-    } deriving (Show)
+    }
+    deriving (Show)
 
-type Located expr = Annotated Region expr
 
-none e = A (None (pretty e)) e
-noneNoDocs e = A (None P.empty) e
+type Located expr =
+    Annotated Region expr
 
-at :: (Pretty expr) => Parsec.SourcePos -> Parsec.SourcePos -> expr
-   -> Annotated Region expr
+
+none :: (Pretty expr) => expr -> Located expr
+none e =
+    A (None (pretty e)) e
+
+
+noneNoDocs :: a -> Located a
+noneNoDocs e =
+    A (None P.empty) e
+
+
+at  :: (Pretty expr)
+    => Parsec.SourcePos
+    -> Parsec.SourcePos
+    -> expr
+    -> Annotated Region expr
 at start end e =
     A (Span (position start) (position end) (pretty e)) e
-    where
-      position loc = Position (Parsec.sourceLine loc) (Parsec.sourceColumn loc)
+  where
+    position loc =
+        Position (Parsec.sourceLine loc) (Parsec.sourceColumn loc)
 
+
+merge :: (Pretty expr) => Located a -> Located b -> expr -> Located expr
 merge (A s1 _) (A s2 _) e =
     A (span (pretty e)) e
-    where
-      span = case (s1,s2) of
-               (Span start _ _, Span _ end _) -> Span start end
-               (Span start end _, _) -> Span start end
-               (_, Span start end _) -> Span start end
-               (_, _) -> None
+  where
+    span =
+      case (s1,s2) of
+        (Span start _ _, Span _ end _) ->
+            Span start end
 
+        (Span start end _, _) ->
+            Span start end
+
+        (_, Span start end _) ->
+            Span start end
+
+        (_, _) -> None
+
+
+mergeOldDocs :: Located a -> Located b -> c -> Located c
 mergeOldDocs (A s1 _) (A s2 _) e =
     A span e
-    where
-      span = case (s1,s2) of
-               (Span start _ d1, Span _ end d2) ->
-                   Span start end (P.vcat [d1, P.text "\n", d2])
+  where
+    span =
+      case (s1,s2) of
+        (Span start _ d1, Span _ end d2) ->
+            Span start end (P.vcat [d1, P.text "\n", d2])
 
-               (Span _ _ _, _) -> s1
-               (_, Span _ _ _) -> s2
-               (_, _) -> None P.empty
+        (Span _ _ _, _) -> s1
 
+        (_, Span _ _ _) -> s2
+
+        (_, _) -> None P.empty
+
+
 sameAs :: Annotated a expr -> expr' -> Annotated a expr'
-sameAs (A annotation _) expr = A annotation expr
+sameAs (A annotation _) expr =
+    A annotation expr
 
+
+getRegionDocs :: Region -> P.Doc
 getRegionDocs region =
     case region of
       Span _ _ doc -> doc
       None doc -> doc
 
+
 instance Pretty Region where
   pretty span = 
       case span of
@@ -68,6 +106,6 @@
               True -> "on line " ++ show (line end) ++ ", column " ++
                       show (column start) ++ " to " ++ show (column end)
 
+
 instance Pretty e => Pretty (Annotated a e) where
   pretty (A _ e) = pretty e
-
diff --git a/src/AST/PrettyPrint.hs b/src/AST/PrettyPrint.hs
--- a/src/AST/PrettyPrint.hs
+++ b/src/AST/PrettyPrint.hs
@@ -38,5 +38,9 @@
           | slen + wlen > 79 = (sentence ++ "\n" ++ spaces ++ word, indent + wlen, " ")
           | otherwise        = (sentence ++ space ++ word, slen + wlen + length space, " ")
 
+instance Error Doc where
+    noMsg = P.empty
+    strMsg = P.text
+
 instance ErrorList Doc where
     listMsg str = [ P.text str ]
diff --git a/src/Elm/Compiler.hs b/src/Elm/Compiler.hs
--- a/src/Elm/Compiler.hs
+++ b/src/Elm/Compiler.hs
@@ -3,7 +3,6 @@
 module Elm.Compiler
     ( version
     , parseDependencies, compile
-    , runtimeDebugPath
     ) where
 
 import Control.Monad.Error (MonadError, throwError)
@@ -16,11 +15,9 @@
 import qualified Elm.Compiler.Module as PublicModule
 import qualified Elm.Compiler.Version as Version
 import Elm.Utils ((|>))
-import qualified Elm.Utils as Utils
 import qualified Generate.JavaScript as JS
 import qualified Parse.Helpers as Help
 import qualified Parse.Module as Parse
-import qualified Paths_elm_compiler as Paths
 
 
 -- VERSION
@@ -70,12 +67,3 @@
               |> List.intersperse ""
               |> unlines
               |> Left
-
-
--- DATA FILES
-
-{-| Path to the debugger runtime.
--}
-runtimeDebugPath :: IO FilePath
-runtimeDebugPath =
-    Utils.getAsset "compiler" Paths.getDataFileName "runtime/debug.js"
diff --git a/src/Generate/JavaScript.hs b/src/Generate/JavaScript.hs
--- a/src/Generate/JavaScript.hs
+++ b/src/Generate/JavaScript.hs
@@ -71,36 +71,47 @@
              hi' <- expression hi
              return $ _List "range" `call` [lo',hi']
 
-      Access e x ->
+      Access e field ->
           do e' <- expression e
-             return $ DotRef () e' (var x)
+             return $ DotRef () e' (var (Var.varName field))
 
-      Remove e x ->
+      Remove e field ->
           do e' <- expression e
-             return $ _Utils "remove" `call` [string x, e']
+             return $ _Utils "remove" `call` [ string (Var.varName field), e' ]
 
-      Insert e x v ->
-          do v' <- expression v
+      Insert e field value ->
+          do value' <- expression value
              e' <- expression e
-             return $ _Utils "insert" `call` [string x, v', e']
+             return $ _Utils "insert" `call` [ string (Var.varName field), value', e' ]
 
-      Modify e fs ->
+      Modify e fields ->
           do e' <- expression e
-             fs' <- forM fs $ \(f,v) -> do
-                      v' <- expression v
-                      return $ ArrayLit () [string f, v']
-             return $ _Utils "replace" `call` [ArrayLit () fs', e']
+             fields' <-
+                forM fields $ \(field, value) ->
+                  do  value' <- expression value
+                      return $ ArrayLit () [ string (Var.varName field), value' ]
 
+             return $ _Utils "replace" `call` [ArrayLit () fields', e']
+
       Record fields ->
-          do fields' <- forM fields $ \(f,e) -> do
-                          (,) f <$> expression e
-             let fieldMap = List.foldl' combine Map.empty fields'
+          do fields' <-
+                forM fields $ \(field, e) ->
+                    (,) (Var.varName field) <$> expression e
+
+             let fieldMap =
+                    List.foldl' combine Map.empty fields'
+
              return $ ObjectLit () $ (prop "_", hidden fieldMap) : visible fieldMap
           where
-            combine r (k,v) = Map.insertWith (++) k [v] r
-            hidden fs = ObjectLit () . map (prop *** ArrayLit ()) .
-                        Map.toList . Map.filter (not . null) $ Map.map tail fs
-            visible fs = map (first prop) . Map.toList $ Map.map head fs
+            combine record (field, value) =
+                Map.insertWith (++) field [value] record
+
+            hidden fs =
+                ObjectLit () . map (prop *** ArrayLit ()) $
+                  Map.toList (Map.filter (not . null) (Map.map tail fs))
+
+            visible fs =
+                map (first prop) (Map.toList (Map.map head fs))
 
       Binop op e1 e2 -> binop region op e1 e2
 
diff --git a/src/Generate/JavaScript/Variable.hs b/src/Generate/JavaScript/Variable.hs
--- a/src/Generate/JavaScript/Variable.hs
+++ b/src/Generate/JavaScript/Variable.hs
@@ -33,9 +33,11 @@
 
 
 varName :: String -> String
-varName x = map (swap '\'' '$') x'
-    where
-      x' = if Set.member x jsReserveds then '$' : x else x
+varName name =
+    let saferName =
+          if Set.member name jsReserveds then '$' : name else name
+    in
+        map (swap '\'' '$') saferName
 
 
 value :: Module.Name -> String -> JS.Expression ()
@@ -56,7 +58,7 @@
     , "interface", "let", "package", "private", "protected", "public"
     , "static", "yield"
     -- reserved by the Elm runtime system
-    , "Elm", "ElmRuntime"
+    , "Elm"
     , "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
     , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
     ]
diff --git a/src/Parse/Declaration.hs b/src/Parse/Declaration.hs
--- a/src/Parse/Declaration.hs
+++ b/src/Parse/Declaration.hs
@@ -21,29 +21,32 @@
 
 typeDecl :: IParser D.SourceDecl
 typeDecl =
- do reserved "type" <?> "type declaration"
-    forcedWS
-    isAlias <- optionMaybe (string "alias" >> forcedWS)
+  do  try (reserved "type") <?> "type declaration"
+      forcedWS
+      isAlias <- optionMaybe (string "alias" >> forcedWS)
 
-    name <- capVar
-    args <- spacePrefix lowVar
-    padded equals
+      name <- capVar
+      args <- spacePrefix lowVar
+      padded equals
 
-    case isAlias of
-      Just _ ->
-          do  tipe <- Type.expr <?> "a type"
-              return (D.TypeAlias name args tipe)
+      case isAlias of
+        Just _ ->
+            do  tipe <- Type.expr <?> "a type"
+                return (D.TypeAlias name args tipe)
 
-      Nothing ->
-          do  tcs <- pipeSep1 Type.constructor <?> "a constructor for a union type"
-              return $ D.Datatype name args tcs
+        Nothing ->
+            do  tcs <- pipeSep1 Type.constructor <?> "a constructor for a union type"
+                return $ D.Datatype name args tcs
 
 
 infixDecl :: IParser D.SourceDecl
 infixDecl = do
-  assoc <- choice [ reserved "infixl" >> return D.L
-                  , reserved "infix"  >> return D.N
-                  , reserved "infixr" >> return D.R ]
+  assoc <-
+      choice
+        [ try (reserved "infixl") >> return D.L
+        , try (reserved "infixr") >> return D.R
+        , try (reserved "infix")  >> return D.N
+        ]
   forcedWS
   n <- digit
   forcedWS
@@ -52,10 +55,17 @@
 
 port :: IParser D.SourceDecl
 port =
-  do try (reserved "port")
-     whitespace
-     name <- lowVar
-     whitespace
-     let port' op ctor expr = do { try op ; whitespace ; ctor name <$> expr }
-     D.Port <$> choice [ port' hasType D.PPAnnotation Type.expr
-                       , port' equals  D.PPDef Expr.expr ]
+  do  try (reserved "port")
+      whitespace
+      name <- lowVar
+      whitespace
+      let port' op ctor expr =
+            do  try op
+                whitespace
+                ctor name <$> expr
+
+      D.Port <$>
+          choice
+            [ port' hasType D.PPAnnotation Type.expr
+            , port' equals  D.PPDef Expr.expr
+            ]
diff --git a/src/Parse/Expression.hs b/src/Parse/Expression.hs
--- a/src/Parse/Expression.hs
+++ b/src/Parse/Expression.hs
@@ -139,62 +139,94 @@
 --------  Normal Expressions  --------
 
 binaryExpr :: IParser Source.Expr
-binaryExpr = Binop.binops appExpr lastExpr anyOp
-  where lastExpr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
-                <|> lambdaExpr
+binaryExpr =
+    Binop.binops appExpr lastExpr anyOp
+  where
+    lastExpr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
+            <|> lambdaExpr
 
+
 ifExpr :: IParser Source.Expr'
-ifExpr = reserved "if" >> whitespace >> (normal <|> multiIf)
-    where
-      normal = do
-        bool <- expr
-        padded (reserved "then")
-        thenBranch <- expr
-        whitespace <?> "an 'else' branch" ; reserved "else" <?> "an 'else' branch" ; whitespace
-        elseBranch <- expr
-        return $ E.MultiIf
-          [ (bool, thenBranch)
-          , (Annotation.sameAs elseBranch (E.Literal . L.Boolean $ True), elseBranch)
-          ]
+ifExpr =
+  do  try (reserved "if")
+      whitespace
+      normal <|> multiIf
+  where
+    normal = do
+      bool <- expr
+      padded (reserved "then")
+      thenBranch <- expr
+      whitespace <?> "an 'else' branch"
+      reserved "else" <?> "an 'else' branch"
+      whitespace
+      elseBranch <- expr
+      return $ E.MultiIf
+        [ (bool, thenBranch)
+        , (Annotation.sameAs elseBranch (E.Literal . L.Boolean $ True), elseBranch)
+        ]
 
-      multiIf = E.MultiIf <$> spaceSep1 iff
-          where iff = do string "|" ; whitespace
-                         b <- expr ; padded arrow
-                         (,) b <$> expr
+    multiIf =
+        E.MultiIf <$> spaceSep1 iff
+      where
+        iff =
+            do  string "|" ; whitespace
+                b <- expr ; padded arrow
+                (,) b <$> expr
 
+
 lambdaExpr :: IParser Source.Expr
-lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
-                whitespace
-                args <- spaceSep1 Pattern.term
-                padded arrow
-                body <- expr
-                return (makeFunction args body)
+lambdaExpr =
+  do  char '\\' <|> char '\x03BB' <?> "anonymous function"
+      whitespace
+      args <- spaceSep1 Pattern.term
+      padded arrow
+      body <- expr
+      return (makeFunction args body)
 
+
 defSet :: IParser [Source.Def]
-defSet = block (do d <- def ; whitespace ; return d)
+defSet =
+  block $
+    do  d <- def
+        whitespace
+        return d
 
+
 letExpr :: IParser Source.Expr'
-letExpr = do
-  reserved "let" ; whitespace
-  defs <- defSet
-  padded (reserved "in")
-  E.Let defs <$> expr
+letExpr =
+  do  try (reserved "let")
+      whitespace
+      defs <- defSet
+      padded (reserved "in")
+      E.Let defs <$> expr
 
+
 caseExpr :: IParser Source.Expr'
-caseExpr = do
-  reserved "case"; e <- padded expr; reserved "of"; whitespace
-  E.Case e <$> (with <|> without)
-    where case_ = do p <- Pattern.expr
-                     padded arrow
-                     (,) p <$> expr
-          with    = brackets (semiSep1 (case_ <?> "cases { x -> ... }"))
-          without = block (do c <- case_ ; whitespace ; return c)
+caseExpr =
+  do  try (reserved "case")
+      e <- padded expr
+      reserved "of"
+      whitespace
+      E.Case e <$> (with <|> without)
+  where
+    case_ =
+      do  p <- Pattern.expr
+          padded arrow
+          (,) p <$> expr
 
+    with =
+      brackets (semiSep1 (case_ <?> "cases { x -> ... }"))
+
+    without =
+      block (do c <- case_ ; whitespace ; return c)
+
+
 expr :: IParser Source.Expr
 expr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
     <|> lambdaExpr
     <|> binaryExpr 
     <?> "an expression"
+
 
 defStart :: IParser [P.RawPattern]
 defStart =
diff --git a/src/Parse/Helpers.hs b/src/Parse/Helpers.hs
--- a/src/Parse/Helpers.hs
+++ b/src/Parse/Helpers.hs
@@ -95,8 +95,10 @@
 
 reserved :: String -> IParser String
 reserved word =
-  (try (string word >> notFollowedBy innerVarChar) >> return word)
-  <?> "reserved word '" ++ word ++ "'"
+  expecting ("reserved word '" ++ word ++ "'") $
+    do  string word
+        notFollowedBy innerVarChar
+        return word
 
 
 -- INFIX OPERATORS
@@ -114,7 +116,6 @@
       guard (op `notElem` [ "=", "..", "->", "--", "|", "\8594", ":" ])
       case op of
         "." -> notFollowedBy lower >> return op
-        "\8728" -> return "."
         _   -> return op
 
 
diff --git a/src/Parse/Module.hs b/src/Parse/Module.hs
--- a/src/Parse/Module.hs
+++ b/src/Parse/Module.hs
@@ -8,49 +8,51 @@
 import qualified AST.Module as Module
 import qualified AST.Variable as Var
 
+
 getModuleName :: String -> Maybe String
 getModuleName source =
-    case iParse getModuleName source of
-      Right name -> Just name
-      Left _     -> Nothing
-    where
-      getModuleName = do
-        optional freshLine
-        (names, _) <- header
-        return (intercalate "." names)
+  case iParse getModuleName source of
+    Right name -> Just name
+    Left _     -> Nothing
+  where
+    getModuleName =
+      do  optional freshLine
+          (names, _) <- header
+          return (intercalate "." names)
 
+
 headerAndImports :: IParser Module.HeaderAndImports
 headerAndImports =
-    do optional freshLine
-       (names, exports) <-
-           option (["Main"], Var.openListing) (header `followedBy` freshLine)
-       imports' <- commitToImports <|> return []
-       return $ Module.HeaderAndImports names exports imports'
-    where
-      commitToImports =
-          do  try (lookAhead $ reserved "import")
-              imports `followedBy` freshLine
+  do  optional freshLine
+      (names, exports) <-
+          option (["Main"], Var.openListing) (header `followedBy` freshLine)
+      imports' <- imports
+      return $ Module.HeaderAndImports names exports imports'
 
+
 header :: IParser ([String], Var.Listing Var.Value)
-header = do
-  try (reserved "module")
-  whitespace
-  names <- dotSep1 capVar <?> "name of module"
-  whitespace
-  exports <- option Var.openListing (listing value)
-  whitespace <?> "reserved word 'where'"
-  reserved "where"
-  return (names, exports)
+header =
+  do  try (reserved "module")
+      whitespace
+      names <- dotSep1 capVar <?> "name of module"
+      whitespace
+      exports <- option Var.openListing (listing value)
+      whitespace <?> "reserved word 'where'"
+      reserved "where"
+      return (names, exports)
 
+
 imports :: IParser [(Module.Name, Module.ImportMethod)]
-imports = option [] ((:) <$> import' <*> many (try (freshLine >> import')))
+imports =
+  many (import' `followedBy` freshLine)
 
+
 import' :: IParser (Module.Name, Module.ImportMethod)
 import' =
-  do reserved "import"
-     whitespace
-     names <- dotSep1 capVar
-     (,) names <$> option (Module.As (intercalate "." names)) method
+  do  try (reserved "import")
+      whitespace
+      names <- dotSep1 capVar
+      (,) names <$> option (Module.As (intercalate "." names)) method
   where
     method :: IParser Module.ImportMethod
     method = as' <|> importing'
@@ -64,25 +66,31 @@
     importing' :: IParser Module.ImportMethod
     importing' = Module.Open <$> listing value
 
+
 listing :: IParser a -> IParser (Var.Listing a)
 listing item =
-  do try (whitespace >> char '(')
-     whitespace
-     listing <- choice [ const Var.openListing <$> string ".."
-                       , Var.Listing <$> commaSep1 item <*> return False
-                       ] <?> "listing of values (x,y,z)"
-     whitespace
-     char ')'
-     return listing
+  do  try (whitespace >> char '(')
+      whitespace
+      listing <-
+          choice
+            [ const Var.openListing <$> string ".."
+            , Var.Listing <$> commaSep1 item <*> return False
+            ] <?> "listing of values (x,y,z)"
+      whitespace
+      char ')'
+      return listing
 
+
 value :: IParser Var.Value
-value = val <|> tipe
-    where
-      val = Var.Value <$> (lowVar <|> parens symOp)
+value =
+    val <|> tipe
+  where
+    val =
+      Var.Value <$> (lowVar <|> parens symOp)
 
-      tipe = do
-        name <- capVar
-        maybeCtors <- optionMaybe (listing capVar)
-        case maybeCtors of
-          Nothing -> return (Var.Alias name)
-          Just ctors -> return (Var.Union name ctors)
+    tipe =
+      do  name <- capVar
+          maybeCtors <- optionMaybe (listing capVar)
+          case maybeCtors of
+            Nothing -> return (Var.Alias name)
+            Just ctors -> return (Var.Union name ctors)
diff --git a/src/Parse/Parse.hs b/src/Parse/Parse.hs
--- a/src/Parse/Parse.hs
+++ b/src/Parse/Parse.hs
@@ -14,51 +14,66 @@
 import qualified Parse.Declaration as Decl
 import Transform.Declaration (combineAnnotations)
 
-freshDef = commitIf (freshLine >> (letter <|> char '_')) $ do
-             freshLine
-             Decl.declaration <?> "another datatype or variable definition"
 
-decls = do d <- Decl.declaration <?> "at least one datatype or variable definition"
-           (d:) <$> many freshDef
+freshDef =
+    commitIf (freshLine >> (letter <|> char '_')) $
+      do  freshLine
+          Decl.declaration <?> "another datatype or variable definition"
 
+
+decls =
+  do  d <- Decl.declaration <?> "at least one datatype or variable definition"
+      (d:) <$> many freshDef
+
+
 program :: OpTable -> String -> Either [P.Doc] M.ValidModule
 program table src =
-    do (M.Module names filePath exs ims sourceDecls) <-
-           setupParserWithTable table programParser src
+  do  (M.Module names filePath exs ims sourceDecls) <-
+          setupParserWithTable table programParser src
 
-       decls <-
-           either (\err -> Left [P.text err]) Right (combineAnnotations sourceDecls)
-       return $ M.Module names filePath exs ims decls
+      decls <-
+          either (\err -> Left [P.text err]) Right (combineAnnotations sourceDecls)
 
+      return $ M.Module names filePath exs ims decls
+
+
 programParser :: IParser M.SourceModule
 programParser =
-  do (M.HeaderAndImports names exports imports) <- Module.headerAndImports
-     declarations <- decls
-     optional freshLine ; optional spaces ; eof
-     return $ M.Module names "" exports imports declarations
+  do  (M.HeaderAndImports names exports imports) <- Module.headerAndImports
+      declarations <- decls
+      optional freshLine ; optional spaces ; eof
+      return $ M.Module names "" exports imports declarations
 
+
 setupParserWithTable :: OpTable -> IParser a -> String -> Either [P.Doc] a
 setupParserWithTable table p source =
-    do localTable <- setupParser parseFixities source
-       case Map.intersection table localTable of
-         overlap | not (Map.null overlap) -> Left [ msg overlap ]
-                 | otherwise -> 
-                     flip setupParser source $ do
-                       putState (Map.union table localTable)
-                       p
-    where
-      msg overlap =
-          P.vcat [ P.text "Parse error:"
-                 , P.text $ "Overlapping definitions for infix operators: " ++
-                          List.intercalate " " (Map.keys overlap)
-                 ]
+  do  localTable <- setupParser parseFixities source
+      case Map.intersection table localTable of
+        overlap | not (Map.null overlap) -> Left [ msg overlap ]
+                | otherwise -> 
+                    flip setupParser source $
+                      do  putState (Map.union table localTable)
+                          p
+  where
+    msg overlap =
+        P.vcat
+          [ P.text "Parse error:"
+          , P.text $
+              "Overlapping definitions for infix operators: "
+              ++ List.intercalate " " (Map.keys overlap)
+          ]
 
-parseFixities = do
-  decls <- onFreshLines (:) [] infixDecl
-  return $ Map.fromList [ (op,(lvl,assoc)) | D.Fixity assoc lvl op <- decls ]
-              
+
+parseFixities =
+  do  decls <- onFreshLines (:) [] infixDecl
+      return $ Map.fromList [ (op,(lvl,assoc)) | D.Fixity assoc lvl op <- decls ]
+
+
 setupParser :: IParser a -> String -> Either [P.Doc] a
 setupParser p source =
     case iParse p source of
-      Right result -> Right result
-      Left err -> Left [ P.text $ "Parse error at " ++ show err ]
+      Right result ->
+          Right result
+
+      Left err ->
+          Left [ P.text $ "Parse error at " ++ show err ]
diff --git a/src/Parse/Pattern.hs b/src/Parse/Pattern.hs
--- a/src/Parse/Pattern.hs
+++ b/src/Parse/Pattern.hs
@@ -25,12 +25,17 @@
           c:_ | isUpper c -> P.Data (Var.Raw v) []
           _               -> P.Var v
 
+
 asPattern :: P.RawPattern -> IParser P.RawPattern
-asPattern pattern = do
-  var <- optionMaybe (try (whitespace >> reserved "as" >> whitespace >> lowVar))
-  return $ case var of
-             Just v -> P.Alias v pattern
-             Nothing -> pattern
+asPattern pattern =
+  do  var <- optionMaybe (try (whitespace >> reserved "as") >> whitespace >> lowVar)
+      case var of
+        Just v ->
+          return (P.Alias v pattern)
+
+        Nothing ->
+          return pattern
+
 
 record :: IParser P.RawPattern
 record = P.Record <$> brackets (commaSep1 lowVar)
diff --git a/src/Transform/AddDefaultImports.hs b/src/Transform/AddDefaultImports.hs
--- a/src/Transform/AddDefaultImports.hs
+++ b/src/Transform/AddDefaultImports.hs
@@ -22,6 +22,7 @@
 defaultImports =
     Map.fromList
     [ ["Basics"] ==> ([], Var.openListing)
+    , ["List"] ==> ([], Var.Listing [Var.Value "::"] False)
     , ["Maybe"] ==> ([], Var.Listing [maybe] False)
     , ["Result"] ==> ([], Var.Listing [result] False)
     , ["Signal"] ==> ([], Var.Listing [signal] False)
diff --git a/src/Type/ExtraChecks.hs b/src/Type/ExtraChecks.hs
--- a/src/Type/ExtraChecks.hs
+++ b/src/Type/ExtraChecks.hs
@@ -20,37 +20,55 @@
 import qualified AST.Type as ST
 import qualified AST.Variable as V
 import qualified Transform.Expression as Expr
+import qualified Type.Hint as Hint
 import qualified Type.Type as TT
 import qualified Type.State as TS
 
+
 throw :: [Doc] -> Either [Doc] a
-throw err = Left [ P.vcat err ]
+throw err =
+  Left [ P.vcat err ]
 
+
 mainType :: TS.Env -> ErrorT [P.Doc] IO (Map.Map String ST.CanonicalType)
 mainType environment =
-  do environment' <- liftIO $ Traverse.traverse TT.toSrcType environment
-     mainCheck environment'
+  do  environment' <- liftIO $ Traverse.traverse TT.toSrcType environment
+      mainCheck environment'
   where
-    mainCheck :: (Monad m) => Map.Map String ST.CanonicalType
-              -> ErrorT [P.Doc] m (Map.Map String ST.CanonicalType)
+    mainCheck
+        :: (Monad m) => Map.Map String ST.CanonicalType
+        -> ErrorT [P.Doc] m (Map.Map String ST.CanonicalType)
     mainCheck env =
       case Map.lookup "main" env of
         Nothing -> return env
         Just typeOfMain
             | tipe `elem` acceptable -> return env
-            | otherwise              -> throwError err
+            | otherwise              -> throwError [ err ]
             where
-              acceptable = [ "Graphics.Element.Element"
-                           , "Signal.Signal Graphics.Element.Element" ]
+              acceptable =
+                  [ "Graphics.Element.Element"
+                  , "Signal.Signal Graphics.Element.Element"
+                  , "Html.Html"
+                  , "Signal.Signal Html.Html"
+                  ]
 
               tipe = PP.renderPretty typeOfMain
-              err = [ P.text "Type Error: 'main' must have type Element or (Signal Element)."
-                    , P.text "Instead 'main' has type:\n"
-                    , P.nest 4 (PP.pretty typeOfMain)
-                    , P.text " " ]
 
+              err =
+                P.vcat
+                  [ P.text "Type Error: 'main' must have one of the following types:"
+                  , P.text " "
+                  , P.text "    Element, Html, Signal Element, Signal Html"
+                  , P.text " "
+                  , P.text "Instead 'main' has type:\n"
+                  , P.nest 4 (PP.pretty typeOfMain)
+                  , P.text " "
+                  ]
+
+
 data Direction = In | Out
 
+
 portTypes :: (Monad m) => Canonical.Expr -> ErrorT [P.Doc] m ()
 portTypes expr =
   case Expr.checkPorts (check In) (check Out) expr of
@@ -120,20 +138,25 @@
               , txt [ "    Json.Values, ", dir "" "first-order functions, ", "and concrete records." ]
               ]
 
+
 occurs :: (String, TT.Variable) -> StateT TS.SolverState IO ()
 occurs (name, variable) =
-  do vars <- liftIO $ infiniteVars [] variable
-     case vars of
-       [] -> return ()
-       var:_ -> do
-         desc <- liftIO $ UF.descriptor var
-         case TT.structure desc of
-           Nothing ->
-               modify $ \s -> s { TS.sErrors = P.text msg : TS.sErrors s }
-           Just _ ->
-               do liftIO $ UF.setDescriptor var (desc { TT.structure = Nothing })
-                  var' <- liftIO $ UF.fresh desc
-                  TS.addError (A.None (P.text name)) (Just msg) var var'
+  do  vars <- liftIO $ infiniteVars [] variable
+      case vars of
+        [] ->
+          return ()
+
+        var : _ ->
+          do  desc <- liftIO $ UF.descriptor var
+              case TT.structure desc of
+                Nothing ->
+                  TS.addHint (P.text msg)
+
+                Just _ ->
+                  do  liftIO $ UF.setDescriptor var (desc { TT.structure = Nothing })
+                      var' <- liftIO $ UF.fresh desc
+                      hint <- liftIO $ Hint.create (A.None (P.text name)) (Just msg) var var'
+                      TS.addHint hint
   where
     msg = "Infinite types are not allowed"
 
diff --git a/src/Type/Hint.hs b/src/Type/Hint.hs
new file mode 100644
--- /dev/null
+++ b/src/Type/Hint.hs
@@ -0,0 +1,35 @@
+module Type.Hint where
+
+import Control.Applicative ( (<$>) )
+import qualified Data.UnionFind.IO as UF
+import Text.PrettyPrint as P
+
+import qualified AST.Annotation as A
+import AST.PrettyPrint (pretty)
+import Type.Type (Descriptor, toSrcType)
+
+
+type Hint = Doc
+
+
+create
+    :: A.Region
+    -> Maybe String
+    -> UF.Point Descriptor
+    -> UF.Point Descriptor
+    -> IO Hint
+create region hint t1 t2 =
+  do  t1' <- pretty <$> toSrcType t1
+      t2' <- pretty <$> toSrcType t2
+      return . foldr ($+$) P.empty $
+         [ P.text "Type mismatch between the following types" <+> pretty region <> P.text ":"
+         , P.text ""
+         , P.nest 8 t1'
+         , P.text ""
+         , P.nest 8 t2'
+         , P.text ""
+         , maybe P.empty (P.nest 4 . P.text) hint
+         , P.text "    It is related to the following expression:"
+         , P.text ""
+         , P.nest 8 $ A.getRegionDocs region
+         ]
diff --git a/src/Type/Inference.hs b/src/Type/Inference.hs
--- a/src/Type/Inference.hs
+++ b/src/Type/Inference.hs
@@ -29,9 +29,9 @@
 
         state <- liftIO $ execStateT (Solve.solve constraint) TS.initialState
 
-        () <- case TS.sErrors state of
-                errors@(_:_) -> throwError errors
-                []           -> return ()
+        () <- case TS.sHint state of
+                hints@(_:_) -> throwError hints
+                []          -> return ()
 
         () <- Check.portTypes (program (body modul))
 
diff --git a/src/Type/Solve.hs b/src/Type/Solve.hs
--- a/src/Type/Solve.hs
+++ b/src/Type/Solve.hs
@@ -9,6 +9,7 @@
 import Type.Type
 import Type.Unify
 import qualified Type.ExtraChecks as Check
+import qualified Type.Hint as Hint
 import qualified Type.State as TS
 import qualified AST.Annotation as A
 
@@ -16,180 +17,197 @@
 -- | Every variable has rank less than or equal to the maxRank of the pool.
 --   This sorts variables into the young and old pools accordingly.
 generalize :: TS.Pool -> StateT TS.SolverState IO ()
-generalize youngPool = do
-  youngMark <- TS.uniqueMark 
-  let youngRank = TS.maxRank youngPool
-      insert dict var = do
-        descriptor <- liftIO $ UF.descriptor var
-        liftIO $ UF.modifyDescriptor var (\desc -> desc { mark = youngMark })
-        return $ Map.insertWith (++) (rank descriptor) [var] dict
+generalize youngPool =
+  do  youngMark <- TS.uniqueMark 
+      let youngRank = TS.maxRank youngPool
+          insert dict var = do
+            descriptor <- liftIO $ UF.descriptor var
+            liftIO $ UF.modifyDescriptor var (\desc -> desc { mark = youngMark })
+            return $ Map.insertWith (++) (rank descriptor) [var] dict
 
-  -- Sort the youngPool variables by rank.
-  rankDict <- foldM insert Map.empty (TS.inhabitants youngPool)
+      -- Sort the youngPool variables by rank.
+      rankDict <- foldM insert Map.empty (TS.inhabitants youngPool)
 
-  -- get the ranks right for each entry.
-  -- start at low ranks so that we only have to pass
-  -- over the information once.
-  visitedMark <- TS.uniqueMark
-  forM (Map.toList rankDict) $ \(poolRank, vars) ->
-      mapM (adjustRank youngMark visitedMark poolRank) vars
+      -- get the ranks right for each entry.
+      -- start at low ranks so that we only have to pass
+      -- over the information once.
+      visitedMark <- TS.uniqueMark
+      forM (Map.toList rankDict) $ \(poolRank, vars) ->
+          mapM (adjustRank youngMark visitedMark poolRank) vars
 
-  -- For variables that have rank lowerer than youngRank, register them in
-  -- the old pool if they are not redundant.
-  let registerIfNotRedundant var = do
-        isRedundant <- liftIO $ UF.redundant var
-        if isRedundant then return var else TS.register var
+      -- For variables that have rank lowerer than youngRank, register them in
+      -- the old pool if they are not redundant.
+      let registerIfNotRedundant var = do
+            isRedundant <- liftIO $ UF.redundant var
+            if isRedundant then return var else TS.register var
 
-  let rankDict' = Map.delete youngRank rankDict
-  Traversable.traverse (mapM registerIfNotRedundant) rankDict'
+      let rankDict' = Map.delete youngRank rankDict
+      Traversable.traverse (mapM registerIfNotRedundant) rankDict'
 
-  -- For variables with rank youngRank
-  --   If rank < youngRank: register in oldPool
-  --   otherwise generalize
-  let registerIfLowerRank var = do
-        isRedundant <- liftIO $ UF.redundant var
-        case isRedundant of
-          True -> return ()
-          False -> do
-            desc <- liftIO $ UF.descriptor var
-            case rank desc < youngRank of
-              True -> TS.register var >> return ()
+      -- For variables with rank youngRank
+      --   If rank < youngRank: register in oldPool
+      --   otherwise generalize
+      let registerIfLowerRank var = do
+            isRedundant <- liftIO $ UF.redundant var
+            case isRedundant of
+              True -> return ()
               False -> do
-                let flex' = case flex desc of { Flexible -> Rigid ; other -> other }
-                liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' })
-                                 
-  mapM_ registerIfLowerRank (Map.findWithDefault [] youngRank rankDict)
+                desc <- liftIO $ UF.descriptor var
+                case rank desc < youngRank of
+                  True -> TS.register var >> return ()
+                  False -> do
+                    let flex' = case flex desc of { Flexible -> Rigid ; other -> other }
+                    liftIO $ UF.setDescriptor var (desc { rank = noRank, flex = flex' })
+                                     
+      mapM_ registerIfLowerRank (Map.findWithDefault [] youngRank rankDict)
 
 
 -- adjust the ranks of variables such that ranks never increase as you
 -- move deeper into a variable.
 adjustRank :: Int -> Int -> Int -> Variable -> StateT TS.SolverState IO Int
 adjustRank youngMark visitedMark groupRank var =
-    do descriptor <- liftIO $ UF.descriptor var
-       case () of
-         () | mark descriptor == youngMark ->
-                do -- Set the variable as marked first because it may be cyclic.
-                   liftIO $ UF.modifyDescriptor var $ \desc ->
-                       desc { mark = visitedMark }
-                   rank' <- maybe (return groupRank) adjustTerm (structure descriptor)
-                   liftIO $ UF.modifyDescriptor var $ \desc ->
-                       desc { rank = rank' }
-                   return rank'
+  do  descriptor <- liftIO $ UF.descriptor var
+      case () of
+        ()  | mark descriptor == youngMark ->
+                do  -- Set the variable as marked first because it may be cyclic.
+                    liftIO $ UF.modifyDescriptor var $ \desc ->
+                        desc { mark = visitedMark }
+                    rank' <- maybe (return groupRank) adjustTerm (structure descriptor)
+                    liftIO $ UF.modifyDescriptor var $ \desc ->
+                        desc { rank = rank' }
+                    return rank'
 
             | mark descriptor /= visitedMark ->
-                do let rank' = min groupRank (rank descriptor)
-                   liftIO $ UF.setDescriptor var (descriptor { mark = visitedMark, rank = rank' })
-                   return rank'
-
-            | otherwise -> return (rank descriptor)
+                do  let rank' = min groupRank (rank descriptor)
+                    liftIO $ UF.setDescriptor var (descriptor { mark = visitedMark, rank = rank' })
+                    return rank'
 
-    where
-      adjust = adjustRank youngMark visitedMark groupRank
+            | otherwise ->
+                return (rank descriptor)
+  where
+    adjust = adjustRank youngMark visitedMark groupRank
 
-      adjustTerm term =
-          case term of
-            App1 a b -> max `liftM` adjust a `ap` adjust b
-            Fun1 a b -> max `liftM` adjust a `ap` adjust b
-            Var1 x -> adjust x
-            EmptyRecord1 -> return outermostRank
-            Record1 fields extension ->
-                do ranks <- mapM adjust (concat (Map.elems fields))
-                   rnk <- adjust extension
-                   return . maximum $ rnk : ranks
+    adjustTerm term =
+        case term of
+          App1 a b -> max `liftM` adjust a `ap` adjust b
+          Fun1 a b -> max `liftM` adjust a `ap` adjust b
+          Var1 x -> adjust x
+          EmptyRecord1 -> return outermostRank
+          Record1 fields extension ->
+              do ranks <- mapM adjust (concat (Map.elems fields))
+                 rnk <- adjust extension
+                 return . maximum $ rnk : ranks
 
 
 solve :: TypeConstraint -> StateT TS.SolverState IO ()
 solve (A.A region constraint) =
   case constraint of
-    CTrue -> return ()
+    CTrue ->
+      return ()
 
-    CSaveEnv -> TS.saveLocalEnv
+    CSaveEnv ->
+      TS.saveLocalEnv
 
-    CEqual term1 term2 -> do
-        t1 <- TS.flatten term1
-        t2 <- TS.flatten term2
-        unify region t1 t2
+    CEqual term1 term2 ->
+      do  t1 <- TS.flatten term1
+          t2 <- TS.flatten term2
+          unify region t1 t2
 
-    CAnd cs -> mapM_ solve cs
+    CAnd cs ->
+      mapM_ solve cs
 
-    CLet [Scheme [] fqs constraint' _] (A.A _ CTrue) -> do
-        oldEnv <- TS.getEnv
-        mapM TS.introduce fqs
-        solve constraint'
-        TS.modifyEnv (\_ -> oldEnv)
+    CLet [Scheme [] fqs constraint' _] (A.A _ CTrue) ->
+      do  oldEnv <- TS.getEnv
+          mapM TS.introduce fqs
+          solve constraint'
+          TS.modifyEnv (\_ -> oldEnv)
 
-    CLet schemes constraint' -> do
-        oldEnv <- TS.getEnv
-        headers <- Map.unions `fmap` mapM (solveScheme region) schemes
-        TS.modifyEnv $ \env -> Map.union headers env
-        solve constraint'
-        mapM Check.occurs $ Map.toList headers
-        TS.modifyEnv (\_ -> oldEnv)
+    CLet schemes constraint' ->
+      do  oldEnv <- TS.getEnv
+          headers <- Map.unions `fmap` mapM (solveScheme region) schemes
+          TS.modifyEnv $ \env -> Map.union headers env
+          solve constraint'
+          mapM Check.occurs $ Map.toList headers
+          TS.modifyEnv (\_ -> oldEnv)
 
-    CInstance name term -> do
-        env <- TS.getEnv
-        freshCopy <-
-            case Map.lookup name env of
-              Just tipe -> TS.makeInstance tipe
-              Nothing
-                | List.isPrefixOf "Native." name -> liftIO (variable Flexible)
-                | otherwise ->
-                    error ("Could not find '" ++ name ++ "' when solving type constraints.")
+    CInstance name term ->
+      do  env <- TS.getEnv
+          freshCopy <-
+              case Map.lookup name env of
+                Just tipe -> TS.makeInstance tipe
+                Nothing
+                  | List.isPrefixOf "Native." name -> liftIO (variable Flexible)
+                  | otherwise ->
+                      error ("Could not find '" ++ name ++ "' when solving type constraints.")
 
-        t <- TS.flatten term
-        unify region freshCopy t
+          t <- TS.flatten term
+          unify region freshCopy t
 
+
 solveScheme :: A.Region -> TypeScheme -> StateT TS.SolverState IO (Map.Map String Variable)
 solveScheme region scheme =
     case scheme of
-      Scheme [] [] constraint header -> do
-          solve constraint
-          Traversable.traverse TS.flatten header
+      Scheme [] [] constraint header ->
+        do  solve constraint
+            Traversable.traverse TS.flatten header
 
-      Scheme rigidQuantifiers flexibleQuantifiers constraint header -> do
-          let quantifiers = rigidQuantifiers ++ flexibleQuantifiers
-          oldPool <- TS.getPool
+      Scheme rigidQuantifiers flexibleQuantifiers constraint header ->
+        do  let quantifiers = rigidQuantifiers ++ flexibleQuantifiers
+            oldPool <- TS.getPool
 
-          -- fill in a new pool when working on this scheme's constraints
-          freshPool <- TS.nextRankPool
-          TS.switchToPool freshPool
-          mapM TS.introduce quantifiers
-          header' <- Traversable.traverse TS.flatten header
-          solve constraint
+            -- fill in a new pool when working on this scheme's constraints
+            freshPool <- TS.nextRankPool
+            TS.switchToPool freshPool
+            mapM TS.introduce quantifiers
+            header' <- Traversable.traverse TS.flatten header
+            solve constraint
 
-          allDistinct region rigidQuantifiers
-          youngPool <- TS.getPool
-          TS.switchToPool oldPool
-          generalize youngPool
-          mapM (isGeneric region) rigidQuantifiers
-          return header'
+            allDistinct region rigidQuantifiers
+            youngPool <- TS.getPool
+            TS.switchToPool oldPool
+            generalize youngPool
+            mapM (isGeneric region) rigidQuantifiers
+            return header'
 
 
+addHint
+    :: A.Region
+    -> Maybe String
+    -> UF.Point Descriptor
+    -> UF.Point Descriptor
+    -> StateT TS.SolverState IO ()
+addHint region hint t1 t2 =
+  do  msg <- liftIO (Hint.create region hint t1 t2)
+      TS.addHint msg
+
+
 -- Checks that all of the given variables belong to distinct equivalence classes.
 -- Also checks that their structure is Nothing, so they represent a variable, not
 -- a more complex term.
 allDistinct :: A.Region -> [Variable] -> StateT TS.SolverState IO ()
-allDistinct region vars = do
-  seen <- TS.uniqueMark
-  let check var = do
-        desc <- liftIO $ UF.descriptor var
-        case structure desc of
-          Just _ -> TS.addError region (Just msg) var var
-              where msg = "Cannot generalize something that is not a type variable."
+allDistinct region vars =
+  do  seen <- TS.uniqueMark
+      forM_ vars $ \var ->
+        do  desc <- liftIO $ UF.descriptor var
+            case structure desc of
+              Just _ ->
+                let msg = "Cannot generalize something that is not a type variable."
+                in
+                    addHint region (Just msg) var var
 
-          Nothing -> do
-            if mark desc == seen
-              then let msg = "Duplicate variable during generalization."
-                   in  TS.addError region (Just msg) var var
-              else return ()
-            liftIO $ UF.setDescriptor var (desc { mark = seen })
-  mapM_ check vars
+              Nothing ->
+                do  when (mark desc == seen) $
+                      do  let msg = "Duplicate variable during generalization."
+                          addHint region (Just msg) var var
+                    liftIO $ UF.setDescriptor var (desc { mark = seen })
 
+
 -- Check that a variable has rank == noRank, meaning that it can be generalized.
 isGeneric :: A.Region -> Variable -> StateT TS.SolverState IO ()
-isGeneric region var = do
-  desc <- liftIO $ UF.descriptor var
-  if rank desc == noRank
-    then return ()
-    else let msg = "Unable to generalize a type variable. It is not unranked."
-         in  TS.addError region (Just msg) var var
+isGeneric region var =
+  do  desc <- liftIO $ UF.descriptor var
+      if rank desc == noRank
+        then return ()
+        else
+          let msg = "Unable to generalize a type variable. It is not unranked."
+          in  addHint region (Just msg) var var
diff --git a/src/Type/State.hs b/src/Type/State.hs
--- a/src/Type/State.hs
+++ b/src/Type/State.hs
@@ -7,11 +7,10 @@
 import qualified Data.Traversable as Traversable
 import qualified Data.UnionFind.IO as UF
 
-import qualified AST.Annotation as A
-import AST.PrettyPrint
-import Text.PrettyPrint as P
+import qualified Type.Hint as Hint
 import Type.Type
 
+
 -- Pool
 -- Holds a bunch of variables
 -- The rank of each variable is less than or equal to the pool's "maxRank"
@@ -40,7 +39,7 @@
     , sSavedEnv :: Env
     , sPool :: Pool
     , sMark :: Int
-    , sErrors :: [P.Doc]
+    , sHint :: [Hint.Hint]
     }
 
 
@@ -51,7 +50,7 @@
     , sSavedEnv = Map.empty
     , sPool = emptyPool
     , sMark = noMark + 1  -- The mark must never be equal to noMark!
-    , sErrors = []
+    , sHint = []
     }
 
 
@@ -65,31 +64,9 @@
     modify $ \state -> state { sPool = f (sPool state) }
 
 
-addError
-    :: A.Region
-    -> Maybe String
-    -> UF.Point Descriptor
-    -> UF.Point Descriptor
-    -> StateT SolverState IO ()
-addError region hint t1 t2 =
-  do err <- liftIO makeError
-     modify $ \state -> state { sErrors = err : sErrors state }
-  where
-    makeError = do
-      t1' <- pretty <$> toSrcType t1
-      t2' <- pretty <$> toSrcType t2
-      return . foldr ($+$) P.empty $
-         [ P.text "Type mismatch between the following types" <+> pretty region <> P.text ":"
-         , P.text ""
-         , P.nest 8 t1'
-         , P.text ""
-         , P.nest 8 t2'
-         , P.text ""
-         , maybe P.empty (P.nest 4 . P.text) hint
-         , P.text "    It is related to the following expression:"
-         , P.text ""
-         , P.nest 8 $ A.getRegionDocs region
-         ]
+addHint :: Hint.Hint -> StateT SolverState IO ()
+addHint hint =
+    modify $ \state -> state { sHint = hint : sHint state }
 
 
 switchToPool :: (MonadState SolverState m) => Pool -> m ()
@@ -109,8 +86,8 @@
 
 saveLocalEnv :: StateT SolverState IO ()
 saveLocalEnv =
-  do  env <- sEnv <$> get
-      modify $ \state -> state { sSavedEnv = env }
+  do  currentEnv <- getEnv
+      modify $ \state -> state { sSavedEnv = currentEnv }
 
 
 uniqueMark :: StateT SolverState IO Int
diff --git a/src/Type/Unify.hs b/src/Type/Unify.hs
--- a/src/Type/Unify.hs
+++ b/src/Type/Unify.hs
@@ -1,37 +1,62 @@
 module Type.Unify (unify) where
 
 import Control.Applicative ((<|>))
-import Control.Monad.State
+import Control.Monad.Error (ErrorT, throwError, runErrorT)
+import Control.Monad.State as State
 import qualified Data.List as List
 import qualified Data.Map as Map
 import qualified Data.Maybe as Maybe
 import qualified Data.UnionFind.IO as UF
+import Text.PrettyPrint (render)
+
 import qualified AST.Annotation as A
 import qualified AST.Variable as Var
 import qualified Type.State as TS
 import Type.Type
 import Type.PrettyPrint
-import Text.PrettyPrint (render)
+import qualified Type.Hint as Hint
 import Elm.Utils ((|>))
 
 
 unify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
-unify region variable1 variable2 = do
+unify region variable1 variable2 =
+  do  result <- runErrorT (unifyHelp region variable1 variable2)
+      either TS.addHint return result
+
+
+-- ACTUALLY UNIFY STUFF
+
+type Unify = ErrorT Hint.Hint (StateT TS.SolverState IO)
+
+
+typeError
+    :: A.Region
+    -> Maybe String
+    -> UF.Point Descriptor
+    -> UF.Point Descriptor
+    -> Unify a
+typeError region hint t1 t2 =
+  do  msg <- liftIO (Hint.create region hint t1 t2)
+      throwError msg
+
+
+unifyHelp :: A.Region -> Variable -> Variable -> Unify ()
+unifyHelp region variable1 variable2 = do
   equivalent <- liftIO $ UF.equivalent variable1 variable2
   if equivalent
       then return ()
       else actuallyUnify region variable1 variable2
 
 
-actuallyUnify :: A.Region -> Variable -> Variable -> StateT TS.SolverState IO ()
+actuallyUnify :: A.Region -> Variable -> Variable -> Unify ()
 actuallyUnify region variable1 variable2 = do
   desc1 <- liftIO $ UF.descriptor variable1
   desc2 <- liftIO $ UF.descriptor variable2
-  let unify' = unify region
+  let unifyHelp' = unifyHelp region
 
       (name', flex', rank', alias') = combinedDescriptors desc1 desc2
 
-      merge1 :: StateT TS.SolverState IO ()
+      merge1 :: Unify ()
       merge1 = liftIO $ do
         if rank desc1 < rank desc2 then UF.union variable2 variable1
                                    else UF.union variable1 variable2
@@ -42,7 +67,7 @@
                  , alias = alias'
                  }
 
-      merge2 :: StateT TS.SolverState IO ()
+      merge2 :: Unify ()
       merge2 = liftIO $ do
         if rank desc1 < rank desc2 then UF.union variable2 variable1
                                    else UF.union variable1 variable2
@@ -55,7 +80,7 @@
 
       merge = if rank desc1 < rank desc2 then merge1 else merge2
 
-      fresh :: Maybe (Term1 Variable) -> StateT TS.SolverState IO Variable
+      fresh :: Maybe (Term1 Variable) -> Unify Variable
       fresh structure = do
         v <- liftIO . UF.fresh $ Descriptor
              { structure = structure
@@ -66,11 +91,11 @@
              , mark = noMark
              , alias = alias'
              }
-        TS.register v
+        lift (TS.register v)
 
       flexAndUnify v = do
         liftIO $ UF.modifyDescriptor v $ \desc -> desc { flex = Flexible }
-        unify' variable1 variable2
+        unifyHelp' variable1 variable2
 
       unifyNumber svar (Var.Canonical home name) =
           case home of
@@ -79,17 +104,17 @@
             _ ->
               let hint = "Looks like something besides an Int or Float is being used as a number."
               in
-                  TS.addError region (Just hint) variable1 variable2
+                  typeError region (Just hint) variable1 variable2
 
       comparableError maybe =
-          TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
+          typeError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
         where
           msg =
             "Looks like you want something comparable, but the only valid comparable\n\
             \types are Int, Float, Char, String, lists, or tuples."
 
       appendableError maybe =
-          TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
+          typeError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
         where
           msg =
             "Looks like you want something appendable, but the only Strings, Lists,\n\
@@ -106,14 +131,14 @@
              case struct of
                Other -> comparableError Nothing
                List v -> do flexAndUnify varSuper
-                            unify' v =<< liftIO (variable $ Is Comparable)
+                            unifyHelp' v =<< liftIO (variable $ Is Comparable)
                Tuple vs
                    | length vs > 6 ->
                        comparableError $ Just "Cannot compare a tuple with more than 6 elements."
                    | otherwise -> 
                        do flexAndUnify varSuper
                           cmpVars <- liftIO $ forM [1..length vs] $ \_ -> variable (Is Comparable)
-                          zipWithM_ unify' vs cmpVars
+                          zipWithM_ unifyHelp' vs cmpVars
 
       unifyAppendable varSuper varFlex =
           do struct <- liftIO $ collectApps varFlex
@@ -122,7 +147,7 @@
                _      -> appendableError Nothing
 
       rigidError var =
-          TS.addError region (Just hint) variable1 variable2
+          typeError region (Just hint) variable1 variable2
         where
           hint =
             "Could not unify rigid type variable '" ++ render (pretty Never var) ++ "'.\n" ++
@@ -153,15 +178,15 @@
 
             (Rigid, _, _, _) -> rigidError variable1
             (_, Rigid, _, _) -> rigidError variable2
-            _ -> TS.addError region Nothing variable1 variable2
+            _ -> typeError region Nothing variable1 variable2
 
   case (structure desc1, structure desc2) of
     (Nothing, Nothing) | flex desc1 == Flexible && flex desc1 == Flexible -> merge
     (Nothing, _) | flex desc1 == Flexible -> merge2
     (_, Nothing) | flex desc2 == Flexible -> merge1
 
-    (Just (Var1 v), _) -> unify' v variable2
-    (_, Just (Var1 v)) -> unify' v variable1
+    (Just (Var1 v), _) -> unifyHelp' v variable2
+    (_, Just (Var1 v)) -> unifyHelp' v variable1
 
     (Nothing, _) -> superUnify
     (_, Nothing) -> superUnify
@@ -170,33 +195,33 @@
         case (type1,type2) of
           (App1 term1 term2, App1 term1' term2') ->
               do merge
-                 unify' term1 term1'
-                 unify' term2 term2'
+                 unifyHelp' term1 term1'
+                 unifyHelp' term2 term2'
           (Fun1 term1 term2, Fun1 term1' term2') ->
               do merge
-                 unify' term1 term1'
-                 unify' term2 term2'
+                 unifyHelp' term1 term1'
+                 unifyHelp' term2 term2'
 
           (EmptyRecord1, EmptyRecord1) ->
               return ()
 
-          (Record1 fields ext, EmptyRecord1) | Map.null fields -> unify' ext variable2
-          (EmptyRecord1, Record1 fields ext) | Map.null fields -> unify' ext variable1
+          (Record1 fields ext, EmptyRecord1) | Map.null fields -> unifyHelp' ext variable2
+          (EmptyRecord1, Record1 fields ext) | Map.null fields -> unifyHelp' ext variable1
 
           (Record1 _ _, Record1 _ _) ->
               recordUnify region fresh variable1 variable2
 
-          _ -> TS.addError region Nothing variable1 variable2
+          _ -> typeError region Nothing variable1 variable2
 
 
 -- RECORD UNIFICATION
 
 recordUnify
     :: A.Region
-    -> (Maybe (Term1 Variable) -> StateT TS.SolverState IO Variable)
+    -> (Maybe (Term1 Variable) -> Unify Variable)
     -> Variable
     -> Variable
-    -> StateT TS.SolverState IO ()
+    -> Unify ()
 recordUnify region fresh variable1 variable2 =
   do  (ExpandedRecord fields1 ext1) <- liftIO (gatherFields variable1)
       (ExpandedRecord fields2 ext2) <- liftIO (gatherFields variable2)
@@ -212,57 +237,57 @@
       let addFieldMismatchError missingFields =
             let msg = fieldMismatchError missingFields
             in
-                TS.addError region (Just msg) variable1 variable2
+                typeError region (Just msg) variable1 variable2
 
       case (ext1, ext2) of
         (Empty _, Empty _) ->
             case Map.null uniqueFields1 && Map.null uniqueFields2 of
               True -> return ()
-              False -> TS.addError region Nothing variable1 variable2
+              False -> typeError region Nothing variable1 variable2
 
         (Empty var1, Extension var2) ->
             case (Map.null uniqueFields1, Map.null uniqueFields2) of
               (_, False) -> addFieldMismatchError uniqueFields2
-              (True, True) -> unify region var1 var2
+              (True, True) -> unifyHelp region var1 var2
               (False, True) ->
                 do  subRecord <- freshRecord uniqueFields1 var1
-                    unify region subRecord var2
+                    unifyHelp region subRecord var2
 
         (Extension var1, Empty var2) ->
             case (Map.null uniqueFields1, Map.null uniqueFields2) of
               (False, _) -> addFieldMismatchError uniqueFields1
-              (True, True) -> unify region var1 var2
+              (True, True) -> unifyHelp region var1 var2
               (True, False) ->
                 do  subRecord <- freshRecord uniqueFields2 var2
-                    unify region var1 subRecord
+                    unifyHelp region var1 subRecord
 
         (Extension var1, Extension var2) ->
             case (Map.null uniqueFields1, Map.null uniqueFields2) of
               (True, True) ->
-                unify region var1 var2
+                unifyHelp region var1 var2
 
               (True, False) ->
                 do  subRecord <- freshRecord uniqueFields2 var2
-                    unify region var1 subRecord
+                    unifyHelp region var1 subRecord
 
               (False, True) ->
                 do  subRecord <- freshRecord uniqueFields1 var1
-                    unify region subRecord var2
+                    unifyHelp region subRecord var2
 
               (False, False) ->
                 do  record1' <- freshRecord uniqueFields1 =<< fresh Nothing
                     record2' <- freshRecord uniqueFields2 =<< fresh Nothing
-                    unify region record1' var2
-                    unify region var1 record2'
+                    unifyHelp region record1' var2
+                    unifyHelp region var1 record2'
 
 
 unifyOverlappingFields
     :: A.Region
     -> Map.Map String [Variable]
     -> Map.Map String [Variable]
-    -> StateT TS.SolverState IO ()
+    -> Unify ()
 unifyOverlappingFields region fields1 fields2 =
-    Map.intersectionWith (zipWith (unify region)) fields1 fields2
+    Map.intersectionWith (zipWith (unifyHelp region)) fields1 fields2
         |> Map.elems 
         |> concat
         |> sequence_
