Assignment versus binding

Chris Angelico rosuav at gmail.com
Thu Oct 6 02:00:57 EDT 2016


On Thu, Oct 6, 2016 at 3:57 PM, Gregory Ewing
<greg.ewing at canterbury.ac.nz> wrote:
> Chris Angelico wrote:
>>
>> Hence my
>> query about how variadic functions and automatic currying work - how
>> does it know whether to curry or run?
>
>
> Calling it "automatic" was probably a bad choice of words.
> I don't mean to imply that Haskell goes around currying
> things behind your back when you don't want it to.

No no, I never meant it like that. Automatic currying can be a huge
boon, but also a stringent limitation.

> The Haskell definition
>
> f x y z = x + y + z
>
> is equivalent to the Python definition
>
> f = lambda x: lambda y: lambda z: x + y + z
>
> To call it, you write
>
> f 1 2 3

Right, and that's fine as long as the function takes a fixed number of
arguments.

> For a variable number of arguments, you could use a list
> instead of a tuple, but again you would need to explicitly
> construct the list when calling.

In other words, it still has to take a fixed number of arguments.
Effectively, variadic functions are _impossible_, so instead you use
argument packaging.

That's not necessarily a bad thing. Not all language features need to
be everywhere. Python has named arguments, and that's great; other
high level languages generally do the same sort of thing with an
options mapping. For example, here's how Pike lets you create a
subprocess:

// Process.Process(command_line, options);
Process.Process("ffmpeg -i file.blk file.mkv", ([
    "cwd": "/path/whatever",
    "uid": 1000, "gid": 1000,
    "timeout": 15,
]));

command_line is either a string (which will be split according to
shell rules) or an array of strings (already split); options is a
mapping. Here's Python's version of that:

# subprocess.run(args, *, **kwargs)
subprocess.run("ffmpeg -i file.blk file.mkv",
    cwd="/path/whatever",
    # uid and gid not supported, but you get the idea
    timeout=15,
)

args is either a string or a list of strings, and options are provided
via keyword arguments. (Interestingly, though Python and Pike offer a
lot of options as you create a subprocess, there are actually very few
that are common. Weird.) This is not a problem. And if variadic
functions are a problem to Haskell, so be it. They don't exist. That
does at least answer my question about "how does Haskell handle
variadic functions and currying" - and, importantly, it answers the
question that comes up periodically of "why can't Python do automatic
currying".

> I hope you can see from this that there's no confusion over
> "whether to curry or run". It all depends on how you define
> the function.

Yeah. No confusion because it does fit into the simple structure that
I described as also working for Python.

There's one other consideration. With Python functions, you often want
to run a function for its side effects and ignore its return value.
With automatic currying, you'd get no error doing that with
insufficient arguments, you'd just be dropping the curried egg - erm,
I mean, function - on the ground. It'd be a subtlety like this:

print("Heading")
print("=======")
print
print("First line of data")
print("Second line of data")

In Py2, this prints a blank line underneath the heading. In Py3, it
merely evaluates the print function, then drops it. This can currently
happen only with the zero argument case, but if you accept
insufficient arguments to mean curry, it could happen any time. That's
somewhat unideal.

ChrisA



More information about the Python-list mailing list