F#组合函数

3
我想学习F#函数式编程,但我在将一些概念从Javascript函数式编程翻译到F#时遇到了一些问题。我有这段代码可以让我像这样在Javascript中组合函数的“管道”:
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);

这种类型的组合在F#中是否可行?我该怎么做呢?

2
很可能你只想要 let mycomp = f1 >> f2 >> f3 >> f4 - Mulan
4个回答

4
假设您需要组合的函数列表在编译时未知,您可以使用fold来组合函数列表。
我看到您已经用reduce找到了一个非常接近的解决方案,它是fold的一种特殊情况,但它没有初始状态,所以当列表为空时会失败。
由于我们无法保证编译时列表不为空,因此我强烈建议您在这种情况下使用fold,并将id函数作为初始状态。
let compose funcs = (fun x -> x |> List.fold (>>) id funcs)

我们可以应用 eta 缩减:
let compose funcs = List.fold (>>) id funcs

再来一次:

let compose = List.fold (>>) id

尽管这最后一步可能会遇到值限制,但它可能会随着其余代码的出现而消失。
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

最后一行会引发值限制错误。 - kaefer
是的,但是有了完整的代码它就会消失。无论如何,我会添加一个注释,谢谢! - Gus

3
这段代码给了我想要的解决方案:
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

1
(fun x -> x |> f) is the same as f – you should be using fold, not reduce - Mulan

2

如果您正在编写一些在编译时就已经确定的固定函数,应直接使用>>

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

let addThree = addOne >> addTwo

1

你说你正在学习F#,所以我冒昧地指出一点 - 这就是你在F#中组合函数的方法:

addOne >> addTwo

在像F#这样的静态类型FP-first语言中进行函数式编程与在非面向此类语言(如JS或C#)中进行相同方法的编码有着非常不同的风格。在这些语言中,必须使用专用函数来编码的东西(例如部分应用或函数组合)直接暴露在语言本身中。
例如,虽然您可以在F#中表达将一系列函数顺序应用于值的相同模式,但您会发现它既过度复杂(因为它可以被简单的函数组合所替代),而且与JS等效比起来功能更弱(因为您无法以这种方式组合具有不同类型的函数,例如您无法组合一个“int -> string”和一个“string -> bool”,因为列表要求所有元素都是相同类型,而JS则完全不关心)。
在JS中,这种模式可能是函数组合的“方式” - 无论如何都需要一个函数,当你在进行操作时,它也可以同时使用一组函数,但是直接将其翻译为F#并不像看起来那么有用。事实证明 - 我在写F#多年后可能只使用过一两次,我不能说这是不可避免的。如果您发现自己想在F#中反复使用此模式,则可能需要重新审视您正在做的事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接