Dobiasd / FunctionalPlus

Functional Programming Library for C++. Write concise and readable C++ code.
http://www.editgym.com/fplus-api-search/
Boost Software License 1.0
2.1k stars 167 forks source link

fplus::compose with yet unknown output type #256

Closed pthom closed 2 years ago

pthom commented 2 years ago

Sorry to bother you today with several issues. Answer when you can, there is no emergency, since I may be bikeshedding a bit.

I tried to compose several generic functions via fplus::compose, but I ended up being forced to specify the container type.

See below, version 3 would be the most intuitive; but it does not compile. Did you encounter this case, and do you know a possible workaround?

TEST_CASE("composition - unknown type")
{
    const std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // Version 1: we force the type inside the compose call
    {
        auto composed = fplus::compose(
            fplus::fwd::keep_if(fplus::is_even<int>),
            fplus::reverse<std::vector<int>> // We need to specify this type for the compilation to pass !
        );
        REQUIRE_EQ(composed(numbers), std::vector<int>{10, 8, 6, 4, 2});
    }

    // Version 2: we use a generic lambda as a proxy: it works, but it is verbose
    {
        auto composed_generic_lambda = [&](const auto& v)
        {
            return fplus::compose(
                fplus::fwd::keep_if(fplus::is_even<int>),
                fplus::reverse<const decltype(v)&>
            )(v);
        };
        REQUIRE_EQ(composed_generic_lambda(numbers), std::vector<int>{10, 8, 6, 4, 2});
    }

    // Version 3: this would be the most intuitive, but does not compile
    {
        auto composed = fplus::compose(
            fplus::fwd::keep_if(fplus::is_even<int>),
            fplus::reverse
        );
        REQUIRE_EQ(composed(numbers), std::vector<int>{10, 8, 6, 4, 2});
    }
}

Here is the error message:

fplus/test/composition_test.cpp:361:25: error: no matching function for call to 'compose'
auto composed = fplus::compose(
    ^~~~~~~~~~~~~~
fplus/include/fplus/composition.hpp:157:6: note: candidate template ignored: 
    substitution failure: deduced incomplete pack <(lambda at fplus/include/fplus/fwd_instances.autogenerated_defines:145:1), 
        (no value)> for template parameter 'Fs'
auto compose(Fs&&... fs)
^
Dobiasd commented 2 years ago

Sorry to bother you today with several issues.

No worries, your issues are good. :)

Answer when you can, there is no emergency, since I may be bikeshedding a bit.

I like the bikeshedding in this case. ;)

Did you encounter this case, and do you know a possible workaround?

Not yet. I'll have a look.

Dobiasd commented 2 years ago

My gut feeling is, that we have no chance to make version 3 work, even though it would be very nice. I think we need an actual function (for example by instantiating a function template) to pass to compose. We can't pass a function template. C++ is (maybe sadly :grin:) not Haskell.

pthom commented 2 years ago

C++ is (maybe sadly 😁) not Haskell.

Yes, exactly

Feel free to close.