Common combinators in JavaScript

January 5, 2024 · View on GitHub

Name#HaskellRamdaSanctuarySignature
identityIididentityIa → a
constantKconstalwaysKa → b → a
applyA($)callI¹(a → b) → a → b
thrushT(&)applyToTa → (a → b) → b
duplicationWjoin²unnest²join²(a → a → b) → a → b
flipCflipflipflip(a → b → c) → b → a → c
composeB(.), fmap²map²compose, map²(b → c) → (a → b) → a → c
substitutionS(<*>)²ap²ap²(a → b → c) → (a → b) → a → c
chainS_³(=<<)²chain²chain²(a → b → c) → (b → a) → b → c
convergeS2³apply2way, liftA2², liftM2²lift2²(b → c → d) → (a → b) → (a → c) → a → d
psiPononon(b → b → c) → (a → b) → a → a → c
fix-point⁴Yfix(a → a) → a

¹) The A-combinator can be implemented as an alias of the I-combinator. Its implementation in Haskell exists because the infix nature gives it some utility. Its implementation in Ramda exists because it is overloaded with additional functionality.

²) Algebras like ap have different implementations for different types. They work like Function combinators only for Function inputs.

³) I could not find a consistent name for these combinators, but they are common enough in the JavaScript ecosystem to justify their inclusion. I named them myself in order to refer to their implementation.

⁴) In JavaScript and other non-lazy languages, it is impossible to implement the Y-combinator. Instead a variant known as the applicative or strict fix-point combinator is implemented. This variant is sometimes rererred to as the Z-combinator. The implementation found in combinators.js is the strictly evaluated "Z" combinator, which needs the extra wrapper around g (g) on the right hand side.