def _merge_with_defaults(params):
    """
    Performs a 2-level deep merge of params with _default_params with corrent
    merging of params for each mark.

    This is a bit complicated since params['marks'] is a list and we need to
    make sure each mark gets the default params.
    """
    marks_params = [
        tz.merge(default, param) for default, param in
        zip(itertools.repeat(_default_params['marks']), params['marks'])
    ] if 'marks' in params else [_default_params['marks']]

    merged_without_marks = tz.merge_with(
        tz.merge, tz.dissoc(_default_params, 'marks'),
        tz.dissoc(params, 'marks')
    )

    return tz.merge(merged_without_marks, {'marks': marks_params})