简体   繁体   中英

F# compose functions

i am trying to learn F# functional programming but i have some issues translating some concepts from Javascript functional programming to F#. I have this code that enables me to compose a "pipeline" of functions in Javascript like this:

const compose = ((functions) => {
    return ((input) => {
        return functions.reduce((ack, func) => {
            return func(ack);
        }, input);
    });
});

const addOne = ((input) => input + 1);
const addTwo = ((input) => input + 2);

const composedFunction = compose([addOne, addTwo]);

const result = composedFunction(2);

console.log(result);

Is it even possible to do this kind of composition in F#? How would i do it?

Assuming that the list of functions you need to compose is not known at compile time, you can use a fold to compose your list of functions.

In your answer I see you found a very close solution with reduce which is a special case of fold but it doesn't have an initial state so when the list is empty it fails.

Since we can't have compile guarantee that the list is not empty I highly recommend you for this scenario using a fold, having the id function as initial state:

let compose funcs = (fun x -> x |> List.fold (>>) id funcs)

We can apply eta reduction:

let compose funcs = List.fold (>>) id funcs

One more time:

let compose = List.fold (>>) id

Although with this last step you will run in the value restriction, but it might disappear with the rest of the code:

let addOne x = x + 1
let addTwo x = x + 2
let compose = List.fold (>>) id
let list = [addOne; addTwo]
let composed = compose list
let elist = []
let composed2 = compose elist

// test
let result = composed 1
let result2 = composed2 1

// val result : int = 4
// val result2 : int = 1

This code got me the solution that i wanted:

let addOne x = x + 1

let addTwo x = x + 2

let compose funcs = 
    (fun x -> x |> List.reduce (>>) funcs)

let list = [addOne; addTwo]

let composed = compose list

let result = composed 1

If you're composing a number of functions that is fixed at compile time you should use >> directly:

let addOne n = n + 1
let addTwo n = n + 2

let addThree = addOne >> addTwo

You say that you're just learning F#, so I'll risk stating the obvious here - this is how you compose functions in F#:

addOne >> addTwo

Functional programming in a statically-typed FP-first language like F# has a very different flavor than encoding the same approach in a language that is not geared to it (like JS or C#). Things that in those languages have to be encoded with dedicated functions, like partial application or function composition, are directly exposed in the language itself.

For instance, while you can express the same pattern of sequentially applying a collection of functions to a value in F#, you will find it both an overkill (because it can be replaced by a simple function composition) and less powerful compared to JS equivalent (because you can't compose functions with different types this way, eg you can't compose an int -> string and a string -> bool because list requires all elements to be the same type, something that JS doesn't care at all about).

In JS this pattern might be "the way" to do function composition - you need a function for it anyway, it might as well take a collection of them while you're at it, but translating it directly into F# is less useful than it seems. Case in point - I have maybe used it once or twice over many years of writing F#, and I can't say it was unavoidable. If you find yourself wanting to use this pattern over and over in F#, you might need to revisit how you're doing things.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM