我有两个功能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
应该如何>>
使用?
我有两个功能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
期望两个值,那么你将得到一个部分应用的函数。
当隐式参数不止一个时,以无点风格编写,即定义没有显式参数的函数会变得很丑陋。
使用正确的运算符组合始终可以完成。但结果会令人失望,您将失去无点样式的主要好处——简单易读。
为了乐趣和学习,我们会试一试。让我们从显式(又名“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
表示- “传递给,然后将结果传递给另一个函数”。x
f
该函数恰好是((<<) g)
,该函数将 afloat -> float
作为参数并返回其与 的组合g
。
g
(排在第二位的构图,这很重要,即使在使用的特定示例中也没有什么区别。)
float -> float
当然,我们的论点是(f x)
的部分应用f
。
因此,以下编译:
let h x = x |> f |> ((<<) g)
现在可以很清楚地简化为
let h = f >> ((<<) g)
当您已经知道它的含义时,这并不是那么糟糕。但是任何有理智的人都更愿意写作和阅读 let h x y = f x y |> g
。