A combinator is a higher-order function that combines functions to coordinate control flow or transformation. It replaces much of the conditional and procedural flow used in imperative code, while keeping business logic inside separate functions. section 4.6
Common combinators handle distinct kinds of coordination:
- identity returns its input unchanged, making it useful for supplying values, testing composition, and extracting data. section 4.6
- tap performs an action such as logging, then returns the original value so the action can sit inside a composition. section 4.6
- alt tries one function and invokes the second only when the first returns a false, null, or undefined value. section 4.6 section 7.2
- seq applies several functions to the same value, while fork applies two functions and combines their results with a join function. section 4.6
Choosing or creating a student
const showStudent = R.compose( append('#student-info'), csv, alt(findStudent, createNewStudent) ); showStudent('444-44-4444'); Here, alt replaces an if-else branch: it uses findStudent when possible and calls createNewStudent only when needed. section 4.6 section 7.2
Combining two calculations
const computeAverageGrade = R.compose(getLetterGrade, fork(R.divide, R.sum, R.length)); computeAverageGrade([99, 80, 89]); //-> 'B' fork sends the same list to R.sum and R.length, then joins those results with R.divide before converting the average to a grade. section 4.6
const debug = R.tap(debugLog); const cleanInput = R.compose(normalize, debug, trim); const isValidSsn = R.compose(debug, checkLengthSsn, debug, cleanInput);
Trace tap inside a composition to see intermediate values without changing the final result. section 4.6



