     helperFunction = Serenade.Helpers[ast.command] or throw SyntaxError "no helper #{ast.command} defined"
     context = { render, model, controller }
     update = ->
-      view.remove() for view in renderedViews
       args = ast.arguments.map((a) -> if a.bound then model[a.value] else a.value)
-      renderedViews = normalize(helperFunction.apply(context, args))
-      dynamic.replace [new Node(ast, element) for { fragment: element } in renderedViews]
+      dynamic.replace([normalize(ast, helperFunction.apply(context, args))])
     for argument in ast.arguments when argument.bound is true
       dynamic.bindEvent(model["#{argument.value}_property"], update)
     update()

    dynamic

# turn a single element, document fragment, compiled view or string, or an
# array of any of these into objects which conform to the interface of a
# compiled view.
normalize = (val) ->
  return [] unless val
  reduction = (aggregate, element) ->
    if typeof(element) is "string"
      div = Serenade.document.createElement("div")
      div.innerHTML = element
      aggregate.push({ fragment: child, remove: -> }) for child in div.childNodes
    else if element.nodeName is "#document-fragment"
      aggregate.push({ fragment: child, remove: -> }) for child in element.childNodes
    else if element instanceof CompiledView
      aggregate.push(element)
    else
      aggregate.push({ fragment: element, remove: -> })
    aggregate
  [].concat(val).reduce(reduction, [])



  helper: (ast, model, controller) ->
    dynamic = new DynamicNode(ast)
    render = (model=model, controller=controller) ->
      fragment = Serenade.document.createDocumentFragment()
      children = compile(ast.children, model, controller)
