【问题标题】:F# compose functionsF# 组合函数
【发布时间】:2018-04-16 18:46:15
【问题描述】:

我正在尝试学习 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# 中进行这种组合吗?我该怎么做?

【问题讨论】:

  • 你很可能只是想要let mycomp = f1 >> f2 >> f3 >> f4

标签: javascript f# functional-programming reduce


【解决方案1】:

假设你需要组合的函数列表在编译时是未知的,你可以使用折叠来组合你的函数列表。

在你的回答中,我看到你找到了一个非常接近的解决方案,reduce 是折叠的一种特殊情况,但它没有初始状态,所以当列表为空时它会失败。

由于我们无法保证列表不为空,因此我强烈建议您在这种情况下使用折叠,将 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

【讨论】:

  • 最后一行将引发Value restriction 错误。
  • 是的,但是使用完整的代码它将消失。无论如何,我会添加一个注释,谢谢!
【解决方案2】:

这段代码得到了我想要的解决方案:

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

【讨论】:

  • (fun x -> x |> f)f 相同——您应该使用fold,而不是reduce
【解决方案3】:

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

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

let addThree = addOne >> addTwo

【讨论】:

    【解决方案4】:

    你说你只是在学习 F#,所以我冒着风险在这里陈述显而易见的事实 - 这就是你在 F# 中组合函数的方式:

    addOne >> addTwo
    

    在 F# 等静态类型的 FP 优先语言中进行函数式编程与在不适合它的语言(如 JS 或 C#)中编码相同的方法具有非常不同的风格。在这些语言中必须使用专用函数编码的东西,例如部分应用程序或函数组合,直接暴露在语言本身中。

    例如,虽然您可以在 F# 中表达将一组函数按顺序应用于一个值的相同模式,但您会发现它既是一种矫枉过正(因为它可以被一个简单的函数组合代替),而且与JS 等价物(因为你不能用这种方式组合不同类型的函数,例如你不能组合 int -> stringstring -> bool 因为列表要求所有元素都是相同的类型,JS 不关心的东西所有关于)。

    在 JS 中,这种模式可能是进行函数组合的“方式”——无论如何你都需要一个函数,它可能会在你使用它的时候收集它们,但是直接将它翻译成 F# 就更少了比看起来有用。举个例子——在编写 F# 的多年中,我可能使用过一次或两次,我不能说这是不可避免的。如果您发现自己想在 F# 中一遍又一遍地使用这种模式,您可能需要重新审视自己的工作方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      相关资源
      最近更新 更多