F# 函数组合,其中第一个函数的元数 >1
F# function composition where the first function has arity >1
我有两个函数 f
和 g
:
let f (x:float) (y:float) =
x * y
let g (x:float) =
x * 2.0
我想组合 (>>
) 它们以获得一个新函数,该函数执行 f
,然后对结果执行 g
。
解决方案应该像这样:
let h x y =
(f x y) |> g
这不起作用:
// Does not compile
let h =
f >> g
>>
应该如何使用?
我想你想实现这个:
let fog x = f x >> g
您不能按顺序直接 f >> g
组合它们,这是有道理的,因为 f 需要两个参数,所以 f x
会导致部分应用函数,但是 g
需要一个值,而不是一个函数。
反之亦然,在您的具体示例中,您甚至可以得到相同的结果,因为您使用的是交换函数。你可以做 g >> f
并且你得到一个导致部分应用函数的组合,因为 g
需要一个值,所以通过将一个值应用到 g
你会得到另一个值(不是函数) 和 f
需要两个值,那么你将得到一个部分应用的函数。
以无点风格编写,即定义没有显式参数的函数,当隐式参数不止一个时,可能会变得难看。
只要运算符的正确组合,总能做到。但结果将是令人失望的,您将失去无点样式的主要好处 - 简单性和易读性。
为了好玩和学习,我们会试一试。让我们从明确的 (a.k.a."pointful") 风格开始,然后从那里开始工作。
(注意:我们将把我们的组合运算符重新排列成它们的显式形式 (>>) (a) (b)
而不是更常见的 a >> b
。这将创建一堆括号,但它会使事情更容易理解,不用担心有时不直观的运算符优先规则。)
let h x y = f x y |> g
let h x = f x >> g
// everybody puts on their parentheses!
let h x = (>>) (f x) (g)
// swap order
let h x = (<<) (g) (f x)
// let's put another pair of parentheses around the partially applied function
let h x = ((<<) g) (f x)
我们到了!看,现在 h x
表达成我们想要的 shape - "pass x
to f
, then pass the result to another function".
那个函数恰好是((<<) g)
,也就是以float -> float
为参数,returns与g
.
组合的函数
(g
出现 second 的组合,这很重要,即使在特定示例中使用它也没有区别。)
我们的float -> float
参数当然是(f x)
,即f
的部分应用。
所以,下面的编译:
let h x = x |> f |> ((<<) g)
现在可以非常清楚地简化为
let h = f >> ((<<) g)
当您已经知道它的含义时, 还不全是这样。但任何有理智的人都更愿意写作和 阅读 let h x y = f x y |> g
.
我有两个函数 f
和 g
:
let f (x:float) (y:float) =
x * y
let g (x:float) =
x * 2.0
我想组合 (>>
) 它们以获得一个新函数,该函数执行 f
,然后对结果执行 g
。
解决方案应该像这样:
let h x y =
(f x y) |> g
这不起作用:
// Does not compile
let h =
f >> g
>>
应该如何使用?
我想你想实现这个:
let fog x = f x >> g
您不能按顺序直接 f >> g
组合它们,这是有道理的,因为 f 需要两个参数,所以 f x
会导致部分应用函数,但是 g
需要一个值,而不是一个函数。
反之亦然,在您的具体示例中,您甚至可以得到相同的结果,因为您使用的是交换函数。你可以做 g >> f
并且你得到一个导致部分应用函数的组合,因为 g
需要一个值,所以通过将一个值应用到 g
你会得到另一个值(不是函数) 和 f
需要两个值,那么你将得到一个部分应用的函数。
以无点风格编写,即定义没有显式参数的函数,当隐式参数不止一个时,可能会变得难看。
只要运算符的正确组合,总能做到。但结果将是令人失望的,您将失去无点样式的主要好处 - 简单性和易读性。
为了好玩和学习,我们会试一试。让我们从明确的 (a.k.a."pointful") 风格开始,然后从那里开始工作。
(注意:我们将把我们的组合运算符重新排列成它们的显式形式 (>>) (a) (b)
而不是更常见的 a >> b
。这将创建一堆括号,但它会使事情更容易理解,不用担心有时不直观的运算符优先规则。)
let h x y = f x y |> g
let h x = f x >> g
// everybody puts on their parentheses!
let h x = (>>) (f x) (g)
// swap order
let h x = (<<) (g) (f x)
// let's put another pair of parentheses around the partially applied function
let h x = ((<<) g) (f x)
我们到了!看,现在 h x
表达成我们想要的 shape - "pass x
to f
, then pass the result to another function".
那个函数恰好是((<<) g)
,也就是以float -> float
为参数,returns与g
.
(g
出现 second 的组合,这很重要,即使在特定示例中使用它也没有区别。)
我们的float -> float
参数当然是(f x)
,即f
的部分应用。
所以,下面的编译:
let h x = x |> f |> ((<<) g)
现在可以非常清楚地简化为
let h = f >> ((<<) g)
当您已经知道它的含义时, 还不全是这样。但任何有理智的人都更愿意写作和 阅读 let h x y = f x y |> g
.