     new AbsNode @varName, @body.reduce()
   @trace apply: (node) ->
     @body.replace @varName, node
-  @trace replace: (varName, node) -> # (\x.\z.x z) \y.y z
-    if varName is @varName
-      # The parameter of this abstraction makes a new context, so no replacement
-      # is needed.
-      @
-    else
-      new AbsNode @varName, @body.replace varName, node
+  @trace replace: (varName, node) ->
+    # TODO rename this abstraction's @varName in @body if @varName is in "node"'s free vars.
+    # The parameter of this abstraction makes a new context, so no replacement
+    # is needed.
+    return @ if varName is @varName
+    new AbsNode @varName, @body.replace varName, node
 
 class ApplyNode extends Node
   constructor: (@left, @right) ->

  @trace reduce: -> @
  @trace apply: -> no
  @trace replace: (varName, node) ->
    if varName is @name
      node
    else
      @

class AbsNode extends Node
  constructor: (@varName, @body) ->

  rightApplyString: -> "(#{@})"
  @trace reduce: ->
    left = @left.reduce()
    (left.apply @right) or new ApplyNode left, @right.reduce()
  @trace apply: -> no
  @trace replace: (varName, node) ->
    new ApplyNode (@left.replace varName, node), (@right.replace varName, node)
