@function __pick-by-callback-iteratee($value, $key, $map) {
    $result: __this('result');
    $predicate: __this('predicate');

    @if __exec($predicate, $value, $key, $map) {
        $_: __this('result', __set($result, $key, $value));
    }

    @return true;
}


@function __pick-by-callback($map, $predicate) {
    $result: ();
    $_: __scope((
        'map': $map,
        'predicate': $predicate,
        'result': $result
    ));
    $pick-by-callback-iteratee: __bind('__pick-by-callback-iteratee');
    $_: __base-for-in($map, $pick-by-callback-iteratee);
    $result: __this('result');
    $_: __scope(false);

    @return $result;
}

@function __pick-by-list($map, $props) {
    $type: type-of($map);
    $map: __to-map($map);
    $result: ();

    @each $key in $props {
        @if (map-has-key($map, $key)) {
            $result: __set($result, $key, __get($map, $key));
        }
    }

    @return if($type == 'list', __to-list($result), $result);
}


@function __pick($map, $predicate: '__identity', $this-arg: null) {
    @if $map == null {
        @return ();
    }

    $map: __to-map($map);

    @return if(__function-exists($predicate),
        __pick-by-callback($map, __bind-callback($predicate, $this-arg, 3)),
        __pick-by-list($map, __base-flatten(($map, $predicate, $this-arg), false, false, 1)));
}


/// Creates a map composed of the picked `$map` properties. Property
/// names may be specified as individual arguments or as lists of property
/// names. If `$predicate` is provided it is invoked for each property of `$map`
/// picking the properties `$predicate` returns truthy for. The predicate is
/// bound to `$this-arg` and invoked with three arguments; (value, key, map).
///
///
/// @access public
/// @group Map
/// @param {Map} $map The source map.
/// @param {Function|String|List(String)} $predicate [_identity] The function invoked per
///  iteration or property names to pick, specified as individual property
///  names or lists of property names.
/// @param {*} $this-arg [null] - The `_this` binding of `$predicate`.
/// @returns {Map} Returns the new map.
/// @example scss
/// $map: ( 'user': 'fred', 'age': 40 );
/// $foo: _pick($map, 'user');
/// // => ( 'user': 'fred' )
/// $foo: _pick($map, _is-string);
/// // => ( 'user': 'fred' )

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