Skip to content

Add @curry decorator #341

Closed
Closed
@sobolevn

Description

@sobolevn

It should not be too hard. partial was pretty much ok, and @curry can reuse a lot of existing stuff.

It should work like so:

from returns.curry import curry

@curry
def sum_two(a: int, b: int) -> int:
    return a + b

assert sum_two(2)(3) == 5
assert sum_two(2, 3)() == 5

Internally we can analyse @curry calls and split function definition into multiple Overloaded cases like in this example:

  • def sum_two() -> def sum_two(a: int, b: int) -> int
  • def sum_two(a: int) -> def sum_two(b: int) -> int
  • def sum_two(a: int, b: int) -> def sum_two() -> int

Implementation can be:

from returns.curry import partial

curry = lambda f: partial(partial, f)

@curry
def test(arg: int, other: str) -> str:
    return str(arg) + other

print(test(1)("a"))  # => 1a
print(test(2, "3")())  # => 23
print(test()(0, "c"))  # => 0c

That's the typing part that is hard.

On the side note, it does not work like in Haskell, where a b c -> x can be applied as a -> b -> c -> x

>>> from returns.curry import partial
>>> 
>>> curry = lambda f: partial(partial, f)
>>> 
>>> @curry
... def test(arg: int, other: str, last: str) -> str:
...     return str(arg) + other + last
... 
>>> test(1)('a')('v')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: test() missing 1 required positional argument: 'last'
>>> test(1)('a', 'v')
'1av'

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions