@function __flow-function($arguments...) {
  $functions: __this("functions");
  $length: __this("length");

  $index: 1;
  $result: __exec(nth($functions, $index), $arguments...);
  $index: $index + 1;

  @while ($index <= $length) {
    $result: __exec(nth($functions, $index), $result);
    $index: $index + 1;
  }

  @return $result;
}

@function __flow($arguments...) {
  $functions: $arguments;
  $length: length($functions);

  @if __is-falsey($length) {
    @return "__noop";
  }

  @if not __list-every($functions, "__function-exists") {
    @error 'FUNC_ERROR_TEXT';
  }

  $_: __scope(
    (
      "functions": $functions,
      "length": $length
    )
  );
  $flow-function: __bind("__flow-function");
  $_: __scope(false);

  @return $flow-function;
}

@function __flow-right-function($arguments...) {
  $functions: __this("functions");
  $index: __this("from-index");

  $result: __exec(nth($functions, $index), $arguments...);
  $index: $index - 1;

  @while ($index > 0) {
    $result: __exec(nth($functions, $index), $result);
    $index: $index - 1;
  }

  @return $result;
}

@function __flow-right($arguments...) {
  $functions: $arguments;
  $from-index: length($functions);

  @if ($from-index < 1) {
    @return "__noop";
  }

  @if not __list-every($functions, "__function-exists") {
    @error 'FUNC_ERROR_TEXT';
  }

  $_: __scope(
    (
      "functions": $functions,
      "from-index": $from-index
    )
  );
  $flow-right-function: __bind("__flow-right-function");
  $_: __scope(false);

  @return $flow-right-function;
}

/// Creates a function that returns the result of invoking the provided
/// functions with the `_this` binding of the created function, where each
/// successive invocation is supplied the return value of the previous.
///
///
/// @access public
/// @group Function
/// @param {Function...} $funcs Functions to invoke.
/// @returns {Function} Returns the new function.
/// @example scss
///     @function add($x, $y) {
///       @return $x + $y;
///     }
///
///     @function square($n) {
///       @return $n * $n;
///     }
///
///     $addSquare: _flow(add, square);
///
///     $foo: _exec($addSquare, 1, 2);
///     // => 9

@function _flow($args...) {
  @return call(get-function("__flow"), $args...);
}

/// This method is like `_flow` except that it creates a function that
/// invokes the provided functions from right to left.
///
///
/// @access public
/// @group Function
/// @param {Function...} $funcs... Functions to invoke.
/// @returns {Function} Returns the new function.
/// @example scss
///     @function add($x, $y) {
///       @return $x + $y;
///     }
///
///     @function square($n) {
///       @return $n * $n;
///     }
///
///     $addSquare: _flow-right(square, add);
///     $foo: _exec($addSquare, 1, 2);
///     // => 9

@function _flow-right($args...) {
  @return call(get-function("__flow-right"), $args...);
}

/// @alias _flow-right

@function _backflow($args...) {
  @return call(get-function("__flow-right"), $args...);
}

/// @alias _flow-right

@function _compose($args...) {
  @return call(get-function("__flow-right"), $args...);
}
