plan(name1=calcs1, name2=calc2...) yields a new calculation plan (object of type
      Plan) that is itself a constructor for the calculation dictionary that is implied by
      the given calc functionss given. The names that are given are used as identifiers for
      updating the calc plan (using the without and using methods).
    plan(arg1, arg2..., name1=calc1, name2=calc2...) additionally initializes the dictionary
      of calculations and names with the calculation plans or dictionaries given as arguments. These
      are collapsed left-to-right.
    plan(imap) yields the plan object for the given IMap imap.

def plan(*args, **kwargs):
    '''
    plan(name1=calcs1, name2=calc2...) yields a new calculation plan (object of type
      Plan) that is itself a constructor for the calculation dictionary that is implied by
      the given calc functionss given. The names that are given are used as identifiers for
      updating the calc plan (using the without and using methods).
    plan(arg1, arg2..., name1=calc1, name2=calc2...) additionally initializes the dictionary
      of calculations and names with the calculation plans or dictionaries given as arguments. These
      are collapsed left-to-right.
    plan(imap) yields the plan object for the given IMap imap.
    '''
    if len(args) == 1 and len(kwargs) == 0 and is_imap(args[0]):
        return args[0].plan
    adict = merge(tuple(arg.nodes if isinstance(arg, Plan) else arg for arg in args),
                  kwargs)
    return Plan(**adict)