繁体   English   中英

Haskell中具有多个参数的部分应用程序

[英]Partial application in Haskell with multiple arguments

给定一些函数f(x1,x2,x3,..,xN),将它部分地应用于几个地方通常很有用。 例如,对于N = 3,我们可以定义g(x)= f(1,x,3)。 但是,Haskell中的标准部分应用程序不能以这种方式工作,只允许我们通过修复其第一个参数来部分应用函数(因为所有函数实际上只接受一个参数)。 有没有简单的方法来做这样的事情:

g = f _ 2 _
g 1 3

输出值为f 1 2 3 当然我们可以做一个lambda函数

g=(\x1 x3 -> f x1 2 x3)

但我觉得这很难读。 例如,在Mathematica中,它就像这样,我觉得很好:

g=f[#1,2,#2]&
g[1,3]

输出f[1,2,3]

编辑:也许我应该更多地谈论动机。 我想在点样式合成中使用这种部分应用的函数,即在这样的表达式中:

h = g. f _ 2 . k

得到h 3 = g(f(k(3),2))

你可以阅读这个问题上如何改变参数的顺序,然后使用部分应用程序,但真正做的,目前在Haskell的干净和清晰的方式就是直接:

g x y = f x 2 y

不,最简单的方法是定义一个lambda。 你可以试着玩flip ,但我怀疑它会比lambda更干净,更简单。 特别是对于更长的参数列表。

最简单(和规范)的方法是定义一个lambda。 如果您在可能的情况下使用有意义的参数名称,则更具可读性

getCurrencyData :: Date -> Date -> Currency -> IO CurrencyData
getCurrencyData fromDate toDate ccy = {- implementation goes here -}

您可以使用lambda语法定义新函数

getGBPData = \from to -> getCurrencyData from to GBP

或没有它

getGBPData from to = getCurrencyData from to GBP

或者你可以使用组合器,但我认为这很难看

getGBPData = \from to -> getCurrencyData from to GBP
           = \from to -> flip (getCurrencyData from) GBP to
           = \from    -> flip (getCurrencyData from) GBP
           = \from    -> (flip . getCurrencyData) from GBP
           = \from    -> flip (flip . getCurrencyData) GBP from
           =             flip (flip . getCurrencyData) GBP

没有一般的方法来做你要求的,但你有时可以使用中缀部分作为flip的替代。 使用你的上一个例子:

g . (`f` 2) . k

此外,我想指出,如果你重新排序函数所采用的参数,它有时会有所帮助。 例如,如果你有一个特别经常部分应用于一个参数的函数,你应该把它作为第一个参数。

假设您正在实现一个代表2D游戏板的数据结构(就像您可能用于Chess程序一样),您可能希望getPiece函数的第一个参数是Chess板,第二个参数是该位置。 我认为被检查的位置可能会比董事会更频繁地更改。 当然,这并不能解决一般问题(也许你想检查一块板上的相同位置),但它可以减轻它。 当我决定一个参数顺序时,这是我考虑的主要问题。

其他需要考虑的事项:

为部分应用程序模式定义辅助函数(本地或全局,如果您发现自己多次使用少量模式)。

fix_2 f a = \x -> f x a
fix1_3 f a b = \x -> f a x b

h = g . fix_2 f 2 . k

不像你假设的“空白”语法那么好,但没关系; 您可以将fix_2读作标识正在使用的部分应用程序方案1的标记。

请注意,您永远不需要任何不修复最后一个参数的部分应用程序方案; 用currying修复4参数函数的第一个和第三个参数(留下两个参数函数)与修复3参数函数的第一个和第三个参数相同。

作为一个更复杂的想法,我相信你应该能够编写一个模板Haskell quasiquoter,它实际上实现了你的“下划线是一个隐含函数的参数”pseudosyntax。 这将允许你写表达式谎言:

h = g . [partial| f _ |] . k

比辅助函数更多的语法开销,你仍然需要一个额外的名称(以识别quasiquoter),但如果您的部分应用程序方案更复杂,可能更容易阅读:

h = g . [partial| f 1 _ 3 4 _ 6 |] . k

这意味着实现模板Haskell代码的一大堆工作,我从来没有做过,所以不知道多少。 但是你有任意的部分应用程序,而辅助函数路由需要为每个模式手动定义。


1请注意,仅修复第二个参数已经具有标准辅助函数: flip 部分适用于第二个参数可能听起来不像是交换前两个参数,但是由于懒惰的评估和讨论,它们实际上是同一个东西!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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