$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] painless currying
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2011-08-24 17:33:16
Dave Abrahams wrote:
> on Wed Aug 24 2011, Eric Niebler <eric-AT-boostpro.com> wrote:
>
>> On 8/24/2011 12:55 PM, Dave Abrahams wrote:
>>>
>>> on Wed Aug 24 2011, Eric Niebler <eric-AT-boostpro.com> wrote:
>>>
>>>> On 8/24/2011 4:28 AM, Thomas Heller wrote:
>>>>>
>>>>> However, the problem comes with function objects having
>>>>> operator() overloads with different arity. Another problem I
>>>>> couldn't solve yet is how to decide which overload gets curryied
>>>>> or not.
>>>>> Consider:
>>>>>
>>>>> struct foo
>>>>> {
>>>>> void operator()(int);
>>>>> void operator()(int, int);
>>>>> };
>>>>>
>>>>> curryable<foo> f;
>>>>> auto curried = f(1); // To curry or not to curry, that is the
>>>>> question
>>>>
>>>> As soon as enough arguments are collected to call the curried
>>>> function, it gets called. So in this case, f(1) calls
>>>> f::operator()(int).
>>>
>>> That's an asymmetry about most currying syntax that I never liked,
>>> at least for C++.
>>
>> Could you explain what you mean by asymmetry here? That my currying
>> code prefers one function over another based on the available
>> arguments?
>
> I mean this, for a ternary function f:
>
> f(x) => doesn't call f
> f(x)(y) => doesn't call f
> f(x)(y)(z) => calls f
>
> That last step looks asymmetric to me.
>
> In a lazy language, f(x)(y)(z) *doesn't* call f... until you actually
> use the result for something... which is more consistent-looking.
>
> I suppose the symmetrical non-lazy version looks like:
>
> f(x) => doesn't call f
> f(x)(y) => doesn't call f
> f(x)(y)(z) => doesn't call f
> f(x)(y)(z)() => calls f
I tend to agree, but can't we have both? What about if the lazy f implicitly converts to its return type through a casting operator? This way we can pass the return type of f(x)(y)(z) as a function object, but make lazy execution of the function object implicit.
f(x) => doesn't call f
f(x)(y) => doesn't call f
result_type result = f(x)(y)(z) => calls f through operator(result_type)
If f had a void return type I guess we would have to force it's call with operator() and use of operator() would otherwise be optional. I suppose forgetting to force would be error prone if people are used to relying on the implicit conversion to force the function call. In general I see no reason not to make a nullary function object castable to its operator() return type, does the loss of type safety hurt us in this case? I like the simplicity of not having the extra () in the simple case where I want to get its result immediately. It may be more intuitive also, but I guess it could do more harm than good if it leads to astonishment.
Just thinking out loud,
Luke