Hyperlinkv0.8.0-beta.28

Function

Function.dualconsteffect/Function.ts:102
<
  DataLast extends (...args: Array<any>) => any,
  DataFirst extends (...args: Array<any>) => any
>(
  arity: Parameters<DataFirst>["length"],
  body: DataFirst
): DataLast & DataFirst
<
  DataLast extends (...args: Array<any>) => any,
  DataFirst extends (...args: Array<any>) => any
>(
  isDataFirst: (args: IArguments) => boolean,
  body: DataFirst
): DataLast & DataFirst

Creates a function that can be called in data-first style or data-last (pipe-friendly) style.

When to use

Use to expose one implementation through both direct and pipe-friendly call styles.

Details

Pass either the arity of the uncurried function or a predicate that decides whether the current call is data-first. Arity is the common case. Use a predicate when optional arguments make arity ambiguous.

Example (Selecting data-first or data-last style by arity)

import { Function, pipe } from "effect"

const sum = Function.dual<
  (that: number) => (self: number) => number,
  (self: number, that: number) => number
>(2, (self, that) => self + that)

console.log(sum(2, 3)) // 5
console.log(pipe(2, sum(3))) // 5

Example (Defining overloads with call signatures)

import { Function, pipe } from "effect"

const sum: {
  (that: number): (self: number) => number
  (self: number, that: number): number
} = Function.dual(2, (self: number, that: number): number => self + that)

console.log(sum(2, 3)) // 5
console.log(pipe(2, sum(3))) // 5

Example (Selecting data-first or data-last style with a predicate)

import { Function, pipe } from "effect"

const sum = Function.dual<
  (that: number) => (self: number) => number,
  (self: number, that: number) => number
>(
  (args) => args.length === 2,
  (self, that) => self + that
)

console.log(sum(2, 3)) // 5
console.log(pipe(2, sum(3))) // 5
combinators
Source effect/Function.ts:10256 lines
export const dual: {
  <DataLast extends (...args: Array<any>) => any, DataFirst extends (...args: Array<any>) => any>(
    arity: Parameters<DataFirst>["length"],
    body: DataFirst
  ): DataLast & DataFirst
  <DataLast extends (...args: Array<any>) => any, DataFirst extends (...args: Array<any>) => any>(
    isDataFirst: (args: IArguments) => boolean,
    body: DataFirst
  ): DataLast & DataFirst
} = function(arity, body) {
  if (typeof arity === "function") {
    return function(this: any) {
      return arity(arguments)
        ? body.apply(this, arguments as any)
        : ((self: any) => body(self, ...arguments)) as any
    }
  }

  switch (arity) {
    case 0:
    case 1:
      throw new RangeError(`Invalid arity ${arity}`)

    case 2:
      return function(a, b) {
        if (arguments.length >= 2) {
          return body(a, b)
        }
        return function(self: any) {
          return body(self, a)
        }
      }

    case 3:
      return function(a, b, c) {
        if (arguments.length >= 3) {
          return body(a, b, c)
        }
        return function(self: any) {
          return body(self, a, b)
        }
      }

    default:
      return function() {
        if (arguments.length >= arity) {
          // @ts-expect-error
          return body.apply(this, arguments)
        }
        const args = arguments
        return function(self: any) {
          return body(self, ...args)
        }
      }
  }
}
Referenced by 897 symbols