polygamous.js
function method(dispatch) {
  var branches      = []
  var baseline      = function(a){ throw noBranchFor(a) }
  var dispatchTable = new DispatchTable()

  dispatch = dispatch || identity

  return makeMethod(function() {
    var value  = dispatch.apply(null, arguments)
    var branch = dispatchTable.getBranch(value).code
              || branchMatching(value, branches).code
              || baseline

    return branch.apply(null, arguments)
  })


  // #### Function makeMethod
  //
  // Adds modification methods to a multi-method.
  //
  // :: method -> method
  function makeMethod(f) {
    f.when     = when
    f.fallback = fallback
    f.remove   = remove
    f.clone    = clone

    return f
  }

  // ### Function when
  //
  // Adds a branch to a multi-method.
  //
  // :: @method => A, (B... -> C) -> method
  function when(condition, f) {
    if (branchMatching(condition, branches).code)  throw ambiguousBranch(condition)

    branches.push({ condition: condition, code: f })
    dispatchTable.add(condition, f)
    return this
  }

  // ### Function fallback
  //
  // Adds a baseline branch, which is evaluated if no other branches
  // match a given dispatch value.
  //
  // :: @method => (A... -> B) -> method
  function fallback(f) {
    baseline = f
    return this
  }

  // ### Function remove
  //
  // Removes a branch from the multi-method.
  //
  // :: @method => A -> method
  function remove(condition) {
    branches = branches.filter(function(a) {
                                 return !equal(condition, a.condition)
                               })
    return this
  }

  // ### Function clone
  //
  // Creates a new multi-method that fallsback to this one.
  //
  // :: @method => Unit -> method
  function clone() {
    var instance = method(dispatch)
    instance.fallback(this)
    return instance
  }
}
function method(dispatch) {
  var branches      = []
  var baseline      = function(a){ throw noBranchFor(a) }
  var dispatchTable = new DispatchTable()

  dispatch = dispatch || identity

  return makeMethod(function() {
    var value  = dispatch.apply(null, arguments)
    var branch = dispatchTable.getBranch(value).code
              || branchMatching(value, branches).code
              || baseline

    return branch.apply(null, arguments)
  })


  // #### Function makeMethod
  //
  // Adds modification methods to a multi-method.
  //
  // :: method -> method
  function makeMethod(f) {
    f.when     = when
    f.fallback = fallback
    f.remove   = remove
    f.clone    = clone

    return f
  }

  // ### Function when
  //
  // Adds a branch to a multi-method.
  //
  // :: @method => A, (B... -> C) -> method
  function when(condition, f) {
    if (branchMatching(condition, branches).code)  throw ambiguousBranch(condition)

    branches.push({ condition: condition, code: f })
    dispatchTable.add(condition, f)
    return this
  }

  // ### Function fallback
  //
  // Adds a baseline branch, which is evaluated if no other branches
  // match a given dispatch value.
  //
  // :: @method => (A... -> B) -> method
  function fallback(f) {
    baseline = f
    return this
  }

  // ### Function remove
  //
  // Removes a branch from the multi-method.
  //
  // :: @method => A -> method
  function remove(condition) {
    branches = branches.filter(function(a) {
                                 return !equal(condition, a.condition)
                               })
    return this
  }

  // ### Function clone
  //
  // Creates a new multi-method that fallsback to this one.
  //
  // :: @method => Unit -> method
  function clone() {
    var instance = method(dispatch)
    instance.fallback(this)
    return instance
  }
}
### Function method  Constructs a multi-method.  :: (A... -> B) -> method