$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