Haskell中多参数的部分应用

Haskell中多参数的部分应用,haskell,partial-application,Haskell,Partial Application,给定一些函数f(x1,x2,x3,…,xN),在几个地方部分应用它通常是有用的。例如,对于N=3,我们可以定义g(x)=f(1,x,3)。但是,Haskell中的标准部分应用程序不是这样工作的,它只允许我们通过修复函数的第一个参数来部分应用函数(因为所有函数实际上只接受一个参数)。有没有简单的方法可以做到这一点: g = f _ 2 _ g 1 3 h = g. f _ 2 . k 输出值为f 1 2 3? 当然我们可以做一个lambda函数 g=(\x1 x3 -> f x1 2 x

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

g = f _ 2 _
g 1 3
h = g. f _ 2 . k
输出值为
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]

编辑:也许我应该多说一些关于动机的事情。我希望在点样式合成中使用这些部分应用的函数,即在如下表达式中:

g = f _ 2 _
g 1 3
h = g. f _ 2 . k

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

不,最简单的方法是定义lambda。你也许可以试着玩,但我怀疑它会比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
您可以阅读如何更改参数顺序,然后使用部分应用程序,但Haskell中目前最干净、最清晰的方法是直接:

g x y = f x 2 y

没有通用的方法来实现您的要求,但有时您可以使用中缀部分作为
翻转的替代方法。使用上一个示例:

g . (`f` 2) . k
另外,我想指出的是,如果您对函数所采用的参数进行重新排序,有时会有所帮助。例如,如果您有一个函数,该函数通常会部分应用于一个参数,那么您可能应该将其作为第一个参数


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

< P>其他要考虑的事情:

为部分应用程序模式定义帮助器函数(如果您发现自己多次使用少量模式,可以是本地的,也可以是全局的)

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

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

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

h = g . [partial| f _ |] . k
与助手函数相比,语法开销更大,并且您仍然需要包含一个附加名称(以标识准注释者),但如果您的部分应用程序方案更复杂,则可能更易于阅读:

h = g . [partial| f 1 _ 3 4 _ 6 |] . k
这意味着需要大量的工作来实现Haskell代码模板,我从来没有做过,不知道有多少。但是,您将拥有任意的部分应用程序方案,而helper函数路由需要为每个模式手动定义



1请注意,仅修复第二个参数已经有一个标准的帮助函数:
flip
。部分应用于第二个参数可能听起来不像是交换前两个参数,但由于懒惰的计算和咖喱,它们实际上是一样的

>代码> g x1 x3= f x1 2 x3至少稍微可读,并且<代码> g x1<代码>=代码> f x1 2 < /代码>更进一步。如果您发现后面位置的参数比前面位置中的参数变化更频繁,请考虑更改参数顺序。谢谢您的回答!然而,我担心我为什么想要这种局部应用程序的主要目的是在内联合成(点样式)中,并且没有一种已知的方法能够提供很好的解决方案。