Partial application in Haskell with multiple arguments

*爱你&永不变心* 提交于 2019-12-04 15:41:54
AndrewC

You could read this question on how to change the order of arguments, then use partial application, but really the cleanest and clearest way of doing that currently in Haskell is just directly:

g x y = f x 2 y

No, the simplest way is to define a lambda. You can probably try and play with flip, but I doubt it would be cleaner and simpler than a lambda. Especially for longer list of arguments.

The simplest (and canonical) way is to define a lambda. It is much more readable if you use meaningful argument names where possible

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

you can define your new function with lambda syntax

getGBPData = \from to -> getCurrencyData from to GBP

or without it

getGBPData from to = getCurrencyData from to GBP

or you can use combinators, but I think this is quite ugly

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

There is no general way to do what you're asking, but you can sometimes use infix sections as an alternate to flip. Using your last example:

g . (`f` 2) . k

Also, I'd like to point out that sometimes it can help if you reorder the arguments your functions take. For instance, if you have a function that will often be partially applied to one argument in particular, you should probably make that the first argument.

Say you are implementing a data structure that represents a 2D game board (like you might for a Chess program), you would probably want the first argument to your getPiece function to be a Chess board and the second argument to be the location. I think it is likely that the location being checked would be changed more often than the board. Of course, this doesn't fix the general issue (maybe you want to check the same location in a list of boards) but it can alleviate it. When I decide on an argument order, this is the main thing I consider.

Other things to consider:

Define helper functions for the partial application patterns (either locally, or globally if you find yourself using a small number of patterns several times).

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

Not quite as nice as your hypothetical "blank" syntax, but okay; you can read fix_2 as a tag identifying the partial application scheme in use1.

Note that you never need any partial application schemes that don't fix the last argument; with currying fixing the first and third arguments of a 4 argument function (leaving a two argument function) is the same as fixing the first and third argument of a 3 argument function.

As a more involved idea, I believe you should be able to write a Template Haskell quasiquoter that actually implements your "underscores are parameters of an implied function" pseudosyntax. This would allow you to write expressions lie this:

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

More syntactic overhead than a helper function, and you still need to involve an additional name (to identify the quasiquoter), but perhaps easier to read if your partial application scheme is much more complicated:

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

It means a bunch of work implementing the Template Haskell code though, which I've never done so no idea how much. But then you'd have arbitrary partial application schemes, whereas the helper function route requires a manual definition for each pattern.


1 Note that fixing only the second argument already has a standard helper function: flip. Partially applying to the second argument might not intuitively sound like swapping the first two arguments, but thanks to lazy evaluation and currying they are actually the same thing!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!