@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...);
}
