www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Currying and composition

reply "bearophile" <bearophileHUGS lycos.com> writes:
In std.functional there is a curry(), that looks more like a 
partial application.

In the Python land I've recently seen a library for a more 
functional style of coding:
https://pypi.python.org/pypi/PyMonad/

I don't like for Python most of the stuff in that PyMonad 
library, but two bits look nice. I quote them here:

<<

 curry
def add(x, y):
     return x + y

 curry
def func(x, y, z):
     # Do something with x, y and z.
     ...

The above fuctions can be partially applied by passing them less 
than their full set of arguments:

add(7, 8)            # Calling 'add' normally returns 15 as 
expected.
add7 = add(7)        # Partial application: 'add7' is a function 
taking one argument.
add7(8)              # Applying the final argument retruns 15...
add7(400)            # ... or 407, or whatever.

# 'func' can be applied in any of the following ways.
func(1, 2, 3)        # Call func normally.
func(1, 2)(3)        # Partially applying two, then applying the 
last argument.
func(1)(2, 3)        # Partially applying one, then applying the 
last two arguments.
func(1)(2)(3)        # Partially applying one, partially applying 
again, then applying the l



Curried functions can be composed with the * operator. Functions 
are applied from right to left:

# Returns the first element of a list.
 curry
def head(aList):
     return aList[0]

# Returns everything except the first element of the list.
 curry
def tail(aList):
     return aList[1:]

second = head * tail        # 'tail' will be applied first, then 
its result passed to 'head'
second([1, 2, 3, 4])        # returns 2


You can also compose partially applied functions:

 curry
def add(x, y):
     return x + y

 curry
def mul(x, y):
     return x * y

comp = add(7) * mul(2)        # 'mul(2)' is evaluated first, and 
it's result passed to 'add(7)'
comp(4)                        # returns 15


Perhaps I'd like in Phobos a "curry" (or another name) template that returns a callable struct that allows both those operations: the currying with arbitrary partial application and the "*" operator to perform function composition (I think the two pieces of functionality go well together despite being different things, because they are both used in a very functional style of coding). Bye, bearophile
Jul 27 2014
parent reply Matt Soucy <msoucy csh.rit.edu> writes:
On 07/27/2014 10:48 AM, bearophile wrote:
 In std.functional there is a curry(), that looks more like a partial
application.
 
 In the Python land I've recently seen a library for a more functional style of
coding:
 https://pypi.python.org/pypi/PyMonad/
 
 I don't like for Python most of the stuff in that PyMonad library, but two
bits look nice. I quote them here:
 
 <<
 
  curry
 def add(x, y):
     return x + y
 
  curry
 def func(x, y, z):
     # Do something with x, y and z.
     ...
 
 The above fuctions can be partially applied by passing them less than their
full set of arguments:
 
 add(7, 8)            # Calling 'add' normally returns 15 as expected.
 add7 = add(7)        # Partial application: 'add7' is a function taking one
argument.
 add7(8)              # Applying the final argument retruns 15...
 add7(400)            # ... or 407, or whatever.
 
 # 'func' can be applied in any of the following ways.
 func(1, 2, 3)        # Call func normally.
 func(1, 2)(3)        # Partially applying two, then applying the last argument.
 func(1)(2, 3)        # Partially applying one, then applying the last two
arguments.
 func(1)(2)(3)        # Partially applying one, partially applying again, then
applying the l
 
 
 
 Curried functions can be composed with the * operator. Functions are applied
from right to left:
 
 # Returns the first element of a list.
  curry
 def head(aList):
     return aList[0]
 
 # Returns everything except the first element of the list.
  curry
 def tail(aList):
     return aList[1:]
 
 second = head * tail        # 'tail' will be applied first, then its result
passed to 'head'
 second([1, 2, 3, 4])        # returns 2
 
 
 You can also compose partially applied functions:
 
  curry
 def add(x, y):
     return x + y
 
  curry
 def mul(x, y):
     return x * y
 
 comp = add(7) * mul(2)        # 'mul(2)' is evaluated first, and it's result
passed to 'add(7)'
 comp(4)                        # returns 15
 

Perhaps I'd like in Phobos a "curry" (or another name) template that returns a callable struct that allows both those operations: the currying with arbitrary partial application and the "*" operator to perform function composition (I think the two pieces of functionality go well together despite being different things, because they are both used in a very functional style of coding). Bye, bearophile
So, in the next release std.functional.curry has been renamed to std.functional.partial: https://github.com/D-Programming-Language/phobos/pull/1979 I was starting to work on a proper curry replacement, but due to some real-life stuff I haven't had time. There's some starting code at https://issues.dlang.org/show_bug.cgi?id=4391 that I was basing mine off of, but I was running into some issues involving static, and a ton of issues with templated functions. This might be something worth looking into? -- Matt Soucy http://msoucy.me/ -- Matt Soucy http://msoucy.me/
Jul 27 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Matt Soucy:

 So, in the next release std.functional.curry has been renamed 
 to std.functional.partial:

 https://github.com/D-Programming-Language/phobos/pull/1979
Oh, good. (And the "sigh" by Andrei is cute).
 I was starting to work on a proper curry replacement,
Is its syntax usage similar to the one I've shown for Python? func(1, 2, 3) func(1, 2)(3) func(1)(2, 3) func(1)(2)(3) Is it a good idea to also mix in the function composition operator overloading? Bye, bearophile
Jul 27 2014
parent reply Matt Soucy <msoucy csh.rit.edu> writes:
On 07/27/2014 12:09 PM, bearophile wrote:
 Matt Soucy:
 
 So, in the next release std.functional.curry has been renamed to
std.functional.partial:

 https://github.com/D-Programming-Language/phobos/pull/1979
Oh, good. (And the "sigh" by Andrei is cute).
I was hoping that was a "sigh, alright I guess this is something we sould do"
 
 I was starting to work on a proper curry replacement,
Is its syntax usage similar to the one I've shown for Python? func(1, 2, 3) func(1, 2)(3) func(1)(2, 3) func(1)(2)(3)
Mine didn't get very far, but the goal was to have that behavior
 Is it a good idea to also mix in the function composition operator overloading?
I'm not so sure about that one - mainly because then it's possible with some functions (the curried ones) but not all (including "regular" and delegates). -- Matt Soucy http://msoucy.me/
Jul 27 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Matt Soucy:

 Is it a good idea to also mix in the function composition 
 operator overloading?
I'm not so sure about that one - mainly because then it's possible with some functions (the curried ones) but not all (including "regular" and delegates).
If you compose (multiply) a "curried" with a regular or a regular with a "curried", you produce a "curried". Is this a problem and not enough? Bye, bearophile
Jul 27 2014
parent Matt Soucy <msoucy csh.rit.edu> writes:
On 07/27/2014 04:59 PM, bearophile wrote:
 Matt Soucy:
 
 Is it a good idea to also mix in the function composition operator overloading?
I'm not so sure about that one - mainly because then it's possible with some functions (the curried ones) but not all (including "regular" and delegates).
If you compose (multiply) a "curried" with a regular or a regular with a "curried", you produce a "curried". Is this a problem and not enough? Bye, bearophile
Try to compose a regular and a regular. If you expect them to all work the same, you're in for a surprise. -- Matt Soucy http://msoucy.me/
Jul 27 2014