problem with curring in python

Terry Reedy tjreedy at udel.edu
Tue Oct 22 06:02:29 EDT 2019


On 10/22/2019 4:58 AM, Antoon Pardon wrote:
> Using python 3.5
> 
> I have been experimenting with curried functions. A bit like in Haskell.
> So I can write the following function:
> 
> def sum4(a, b, c, d):
>      return a + b + c + d
> 
> summing = curry(sum4)
> 
> print summing(1)(2)(3)(4) # this prints 10.
> 
> The problem is I need the signature of the original function in order to
> know when to finally call the function and return the actual result.
> However buildin functions don't have a

I believe most do.

 >>> help(abs)
Help on built-in function abs in module builtins:

abs(x, /)
     Return the absolute value of the argument.

 >>> abs.__text_signature__
'($module, x, /)'
 >>> import inspect
 >>> inspect.signature(abs)
<Signature (x, /)>

The exceptions are those with complicated signatures still given in 
multiple lines in the docstring since the true signature would be too 
complicated for humans to digest.  Example:

 >>> help(bytes)
Help on class bytes in module builtins:

class bytes(object)
  |  bytes(iterable_of_ints) -> bytes
  |  bytes(string, encoding[, errors]) -> bytes
  |  bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer
  |  bytes(int) -> bytes object of size given by the parameter 
initialized with null bytes
  |  bytes() -> empty bytes object

The latter 5 lines are from bytes.__doc__.  signature(bytes) raises 
ValueError.  Note that parameter 1 is the union of 4 types, 3 
iterable_of_ints, bytes_or_buffer, int, and string (str_or_bytes), 2 of 
which are unions themselves and 2 of which are non-disjoint. 
Furthermore, the presence of 1 or 2 more args is only valid if the 1st 
arg is a string.  The concept of currying does not really apply to this 
situation very well.

In other words, the cases without signatures should probably not be curried.

> signature. Here below is my
> current experimental implementation. Any ideas for an other approach?
> 
>      def curry(func, *args):
>          arg_len = len(signature(func).parameters)
>          if arg_len <= len(args):
>              return func(*args)
>          else:
>              return CurryType(func, arg_len, args)
> 
>      class CurryType:
>          def __init__(self, func, arg_len, args):
>              self.func = func
>              self.arg_len = arg_len
>              self.args = list(args)
> 
>          def __call__(self, *args):
>              args = self.args + list(args)
>              if self.arg_len <= len(args):
>                  return self.func(*args)
>              else:
>                  return CurryType(self.func, self.arg_len, args)



-- 
Terry Jan Reedy




More information about the Python-list mailing list