function composition

Redlang documentation | fundamentals

In mathematics, function composition is the operation that takes two functions g and f and produces a function h such that h(x) = g(f(x)) (the function g is applied to the result of the application of the function f to x). -- Wikipedia

Usage

Basics

Syntax of function composition in Red lang is close to math syntax, you can even use ∘ symbol in composite name, for example:


f: function[x][x + 1]
g: function[x][x * 2]
g∘f: function[x][g f x]
r: g∘f 2
?? r     
    

will output:

6

The special case of function with lit-word argument syntax

Usually, you'd better use parenthesis to indicate precedence for some function with lit-word argument, like the popup function for example :


do https://redlang.red/popup
help popup

will show that it accepts '~param>message (' specifies lit(eral) word syntax) and not ~param>message (get word) syntax:

ARGUMENTS:
     '~param>message [any-type!]         
    

in that case without using () means you'll pass the symbol and not the value, that's why

do https://redlang.red/popup
popup ask "message: "

will popup the literal symbol

ask

whereas:

do https://redlang.red/popup
popup (ask "message: ")
    

will popup what you'd have entered as message as parens will evaluate the expression before passing it as argument.

Practical Examples of Function Composition

Aggregate file names from multiple directories with collect/keep and compose

For example let's aggregate %../build/ and %../ci/ folders with collect/keep and compose:


files: collect [
    keep compose [(read %../build/) (read %../ci/)]
]
?? files
    

This will output for example:

files: [%assemble.red %build.red %production.config %production.red %release.red]

Aggregate file paths from multiple directories with collect/keep and compose

To insert full path for a file depending if it is in %../build/ or %../ci/ folder, you have to nest collect within collect with compose, insert, head and clean-path functions:


files: collect [
    keep compose [
        (collect [foreach file read %../build/ [keep head insert file clean-path %../build/ ]]) 
        (collect [foreach file read %../ci/ [keep head insert file clean-path %../ci/]]) 
    ]
]
?? files
    

This will output for example:

files: [%/d/projects/Red/redlang.red/src/cache.inc/build/assemble.red %/d/projects/Red/redlang.red/src/cache.inc/build/build.red %/d/projects/Red/redlang.red/src/cache.inc/ci/production.config %/d/projects/Red/redlang.red/src/cache.inc/ci/production.red %/d/projects/Red/redlang.red/src/cache.inc/ci/release.red]

Note: if you need to exclude folder type, you can use:

unless dir? file [...]

so code would be:


files: collect [
    keep compose [
        (collect [foreach file read %../build/ [unless dir? file [keep head insert file clean-path %../build/] ]]) 
        (collect [foreach file read %../ci/ [unless dir? file [keep head insert file clean-path %../ci/] ]) 
    ]
]
    

Learn side by side

Red // javascript:

In Javascript

You'd write for example:


// function composition in javascript
const f = x => x + 1;
const g = x => x * 2;
const doGafterF = x => {
  const afterF = f(x);
  const afterG = g(afterF);
  return afterG;
};

console.log(doGafterF(2)); // 6        
    

In Red

You'd write for the same example:


f: function[x][x + 1]
g: function[x][x * 2]
g∘f: function[x][g f x]
r: g∘f 2
?? r ; 6        
    

References

official documentation:

function composition | wikipedia