@function __base-filter-iteratee($value, $index, $collection) {
    $result: __this('result');
    $predicate: __this('predicate');
    $iteration: __exec($predicate, $value, $index, $collection);

    @if __is-truthy($iteration) {
        $_: __this('result', append($result, $value));
    }

    @return null;
}


@function __base-filter($collection, $predicate) {
    $_: __scope((
        'result': (),
        'predicate': $predicate
    ));
    $_: __base-each($collection, '__base-filter-iteratee');
    $result: __this('result');
    $_: __scope(false);

    @return $result;
}


@function __list-filter($list, $predicate) {
    $index: 1;
    $length: length($list);
    $result: ();

    @while ($index <= $length) {
        $value: nth($list, $index);
        $iteration: __exec($predicate, $value, $index, $list);

        @if (__is-truthy($iteration)) {
            $result: append($result, $value);
        }

        $index: $index + 1;
    }

    @return $result;
}


@function __filter($collection, $predicate: __identity, $this-arg: null) {
    $function: if(__is-list($collection), '__list-filter', '__base-filter');
    $predicate: __get-callback($predicate, $this-arg, 3);

    @return __call($function, $this-arg, $collection, $predicate);
}


/// Iterates over elements of `$collection`, returning a list of all elements
/// `$predicate` returns truthy for. The predicate is bound to `$this-arg` and
/// invoked with three arguments; (value, index|key, collection).
/// 
/// If a property name is provided for `$predicate` the created `_property`
/// style callback returns the property value of the given element.
/// 
/// If a value is also provided for `$this-arg` the created `_matches-property`
/// style callback returns `true` for elements that have a matching property
/// value, else `false`.
/// 
/// If a map is provided for `$predicate` the created `_matches` style
/// callback returns `true` for elements that have the properties of the given
/// object, else `false`.
///
///
/// @access public
/// @group Collection
/// @param {List|Map|string} $collection - The collection to iterate over.
/// @param {Function|Map|string} $predicate [_identity] - The function invoked
///  per iteration.
/// @param {*} $this-arg [null] - The `_this` binding of `$predicate`.
/// @returns {List} Returns the new filtered list.
/// @example scss
///     @function is-even($value, $args...) {
///         @return $value % 2 == 0;
///     }
///     
///     $foo: _filter((4, 5, 6), is-even);
///     // => (4, 6)
///     
///     $users: (
///       ( 'user': 'barney', 'age': 36, 'active': true ),
///       ( 'user': 'fred',   'age': 40, 'active': false )
///     );
///     
///     // using the `_matches` callback shorthand
///     $foo: _pluck(_filter($users, ( 'age': 36, 'active': true )), 'user');
///     // => ('barney',)
///     
///     // using the `_matches-property` callback shorthand
///     $foo: _pluck(_filter($users, 'active', false), 'user');
///     // => ('fred',)
///     
///     // using the `_property` callback shorthand
///     $foo: _pluck(_filter($users, 'active'), 'user');
///     // => ('barney',)

@function _filter($args...) {
    @return call(get-function('__filter'), $args...);
}


/// @alias _filter

@function _select($args...) {
    @return call(get-function('__filter'), $args...);
}
