Thread overview
Currying and composition
Jul 27, 2014
bearophile
Jul 27, 2014
Matt Soucy
Jul 27, 2014
bearophile
Jul 27, 2014
Matt Soucy
Jul 27, 2014
bearophile
Jul 27, 2014
Matt Soucy
July 27, 2014
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
July 27, 2014
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/
July 27, 2014
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
July 27, 2014
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/
July 27, 2014
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
July 27, 2014
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/