boostorg / hof Goto Github PK
View Code? Open in Web Editor NEWHigher-order functions for c++
Home Page: http://boost-hof.readthedocs.io/
License: Other
Higher-order functions for c++
Home Page: http://boost-hof.readthedocs.io/
License: Other
Oh, I believe I have found why I don't understand. The template parameters TS are not part of the function apply
This
template<class F, class... Ts>
constexpr auto apply(F&& f, Ts&&... xs);
should be
template<class F>
constexpr auto apply(F&& f);
The semantics given us
assert(apply(f)(xs...) == f(xs...));
But the usage is incompatible
assert(fit::apply(sum_f(), 1, 2) == 3);
that I believe should be
assert(fit::apply(sum_f())(1, 2) == 3);
Unfortunately the implementation is not inline at all.
It is not clear if the two previous lines are needed to make sum
pipable.
FIT_STATIC_FUNCTION(sum) = sum_f();
and
const constexpr pipable_adaptor<sum_f> sum = {};
It would be great to have a link to the complete example in the example/tutorial directory.
BTW, why const constexpr
?
Hi, first of all, thanks so much for your speedy response on my previous issue!
It seems like the newest commit 65c8d3f broke the following code that tries to pass expression made by placeholders as a function object to a pipable object.
Removing the constexpr
from the constructor and operator ()
in left
, right
, and partial_ap
seems to fix it.
The code:
vector<int> vectorValues = { 1, 2, 3, 4, 5 };
auto filter =
pipable(
[] (auto input, auto pred) {
decltype(input) output(input.size());
output.erase(
::std::copy_if(
::std::begin(input),
::std::end(input),
::std::begin(output),
pred
),
::std::end(output)
);
return output;
}
);
vectorValues
| filter(_1 > 1);
I get the following error message on Clang3.5
./fit/placeholders.h:245:40: error: call to implicitly-deleted copy constructor of 'fit::detail::pipe_closure<(lambda at test.cpp:103:13), fit::detail::pack_base<fit::detail::seq<0>,
fit::detail::lazy_invoker<fit::operators::greater_than, fit::detail::pack_base<fit::detail::seq<0, 1>, fit::detail::simple_placeholder<1>, int> > &&> >'
constexpr partial_ap(const T& x) : val(x)
^ ~
./fit/placeholders.h:294:23: note: in instantiation of member function 'fit::detail::unamed_placeholder::partial_ap<fit::detail::pipe_closure<(lambda at test.cpp:103:13),
fit::detail::pack_base<fit::detail::seq<0>, fit::detail::lazy_invoker<fit::operators::greater_than, fit::detail::pack_base<fit::detail::seq<0, 1>, fit::detail::simple_placeholder<1>, int> > &&> >,
fit::detail::unamed_placeholder::right<fit::operators::bit_or> >::partial_ap' requested here
FIT_FOREACH_BINARY_OP(FIT_UNAMED_PLACEHOLDER_BINARY_OP)
This proposal is related to match
/conditional
. A reference would be welcome.
Note that P0051 - C++ match function is related to visitation.
typo functinal
I believe that you need to define before what a function is before defining what is a function adaptor.
"A function adaptor takes a function(or functions) and returns a new function "
Is it a Callable?
The apply_eval
function documents that it requires Evaluatable
arguments. I wasn't able to find that concept, what is it? Similarly, the eval
function requires EvaluatableFunctionObject
, which does not seem to be documented.
I'm wondering if we need to name the result of the adaptors, or just say that it is an unspecified function with a specific signature that behaves as ....
What is the advantage to giving it a name?
Giving a name to the result type would imply to add the description of all of its operations.
Most adaptors require FunctionObject
s. Is there any reason not to allow arbitrary Callable
s, and to use something like std::invoke
to call the functions instead? That would be slightly more flexible, as one could use member pointers & al instead of regular function objects. However, there's probably a non-negligible compile-time penalty if this is supported everywhere in the library.
It is not clear from the description what would be the result of
auto x = construct<vector>()(1);
I have a make function that can also take a type-constructor so that we can
auto x = make<expected<_, error_code>>(1);
auto x = make<unique_ptr<_, MyDeleter>>()(1);
Of course, we need some kind of customization from the user.
Hi, when I tried the unnamed placeholder in your library in the following expression:
auto comp = _ > 1;
assert(comp(2) == true);
assert(comp(1) == false);
I get false
for both the comparisons.
Replacing _
with the normal placeholder _1
would return true for comp(2) as intended. Expressions that produce a value such as _ + _
and _ * 10
also work as intended.
I looked into the placeholder code, but couldn't really figure out why the boolean expression didn't work as intended. Could you please take a look?
It is not clear from the documentation that your library can consider an oveload set as a function
and that match
and conditional
are overload set factories and that their result can be considered as functions arguments for the other functions. I believe that this is very important.
I suggest to use signatures to describe oveloads sets as e.g.
(T1->U1 T2->U2)
could represent an overloaded set that can transform a T1
on a U1
and a T2
on a U2
.
The signature of by
could be for the binary case
by :: ( (T1->U1 T2->U2) (U1 U2 -> V) ) -> ((T1 T2) -> V)
The documentation must state this clearly.
I don't see the differences between the two function
assert(decorate(f)(x)(g)(xs...) == f(x, g, xs...));
assert(partial(f)(xs...)(ys...) == f(xs..., ys...));
implicit
is not an adaptor as the other as it is a class not a function.
I would like to have in the documentation a more comprehensive description of how implicit
behaves.
Is something like that
implicit<TC>(xs....).operator X() <==> TC<X>(xs...).operator X()
Is this compatible with INVOKE from the standard?
The documentation of if_
is not clear to me. It says
The if_ function decorator applies a boolen condition to the function.
However, it seems to me like what it does is make the function callable only when the predicate is satisfied, or something like that. Also, there's a typo in the above quote (boolen
).
It is not clear to what function you are referring to in Recursive section
"So the first parameter of the function will be the function itself:"
If it is to the fix
function, it seems not useful as fix has only one parameter, isn't it?
In http://fit.readthedocs.org/en/latest/index.html I can see
"Fit is a header-only C++11 library"
" Fit takes advantages of modern C++11/C++14 features"
Does Fit need some C++14 support? If suspect that not because it is a C++11library.
This is confusing.
IIUC match and conditional return today a lambda, but they could as well return a function object in the future, isn't it?
I will replace the macro FIT_STATIC_LAMBDA_FUNCTION
by a more specific one,e.g. FIT_STATIC_CONDITIONAL_FUNCTION.
FIT_STATIC_LAMBDA_FUNCTION(print) = conditional( ...);
The same for match.
There are two variants of fold, left associative versus right.
What about naming them fold_left
and fold_right
?
Given an adaptor that results in a variadic function as compress
compress:: F A -> (B.... -> A)
we could define it by using a function having a tuple as parameter
compress(f, z)(xs...) = fold(f, z, forward_as_tuple(xs...))
I believe that we have already this kind of fold fuctions in Hana.
So given
fold: F A H -> A
partial(fold, F, A)
would almost behave like compress except that partial(fold, F A)
takes a tuple as parameter and compress takes a variadic number of arguments. So we can see compress something like
compress(f, a) = compose(partial(fold, f, a), forward_as_tuple)
I'm not saying that compress is not useful, even if the name has not too much relation to what is behind the scenes. I would say that it could be a useful shortcut when the user doesn't has already a sequence or a tuple.
Of course, in C++ we don't want to pay more than needed, so the implementation should be more efficient than using the right hand side.
It would be fanny to have some performance measures. This is micro-benchmarking, but having the figures would help the user to understand the trade-offs.
$make by
[100%] Building CXX object CMakeFiles/by.dir/test/by.cpp.o
fit/test/by.cpp:24:20: error: no matching function for call to object of type
'by_adaptor<std::__1::__mem_fn<int foo::*>, fit::operators::add>'
FIT_TEST_CHECK(fit::by(std::mem_fn(&foo::x), add)(foo(1), foo(2)) == 3);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fit/test/test.h:66:35: note: expanded from macro 'FIT_TEST_CHECK'
#define FIT_TEST_CHECK(...) if (!(__VA_ARGS__)) std::cout << "*****FAILED: " << #__VA_ARGS__ << "@" << __FILE__ << ": " << __LINE__ ...
^
fit/./fit/by.h:86:20: note: candidate template ignored: substitution failure [with Ts = <foo, foo>]: no
matching function for call to object of type 'const std::__1::__mem_fn<int foo::*>'
constexpr auto operator()(Ts&&... xs) const FIT_RETURNS
^
1 error generated.
make[3]: *** [CMakeFiles/by.dir/test/by.cpp.o] Error 1
make[2]: *** [CMakeFiles/by.dir/all] Error 2
make[1]: *** [CMakeFiles/by.dir/rule] Error 2
make: *** [by] Error 2
Compiler:
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
unique_ptr<sum> psum;
int r = indirect(psum)(3,2);
It seems that there is a precondition missing. It should be more explicit the operation used on the parameter, in this case operator*()
I guess.
Applicatives
have a similar and safer function that returns another Applicative having the same type-constructor.
(<*>) :: f (a -> b) -> f a -> f b
if f is also a Monad
<*>
is equal to ap
auto r = ap(psum, make_unique(3,2)); // decltype x is unique_ptr<int>
As defined, the parameter should be a model of a PossiblyNull
or PossyblyValued
concept supporting the dereference function.
Boost normally uses the .hpp
extension for its headers. It would be nice to make sure that Fit follows that, in preparation for the review.
capture(xs...)(f)(ys...) <==> f(xs..., ys...)
Another way is to define it as
capture(xs...)(f) <==> partial(f, xs...)
Is there a difference in performances, between the 3 expressions?
capture(xs...)(f)(ys...) <==> f(xs..., ys...) <==> partial(f, xs...)(ys...)
BTW, the example would clearer if you use different number
assert(f(5, 8) == std::make_tuple(std::make_pair(1, 5), std::make_pair(2, 8)));
or even different types.
Needed for the std::reference_wrapper
used by unwrap_reference
.
Compiler:
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
Can you explain the "the static initialization order fiasco"?
I'm not sure what you mean by that. An example would be helpful!
As we discussed at CppCon, it might be a good idea to stop using the term dependent typing in the documentation in favor of another word which is not already used in math/functional programming.
I believe that it is important for the user to know how the specification of the reference section is structured. I will add a section to describe it.
I like the way the semantic is given. This is almost the equivalent as the as if on the standard
assert(by(p, f)(xs...) == f(p(xs)...));
The signature of by
seems to be
by :: ( (T->U) (V -> W) ) -> ((X...) -> W)
by :: p f -> xs... -> w)
where U is convertible to V and X is convertible to T.
But I believe that it supports more than that, I don't believe the library is forcing all types in X... to be the same.
I like the way the semantic is given
assert(by(p, f)(xs...) == f(p(xs)...));
p(xs)
must be well formed, p
should have an overload taking a type convertible from decltype(xs) for each xs.
f(p(xs)...))
must be well formed, so f should have an overload taking types V... convertible from decltype(p(xs))...
This means that p
Wouldn't the by
function has a signature something like
by :: ( ((T->U)...) (V... -> W) ) -> ((X...) -> W)
Are there any constraints on the types T..,U..., V..., X..., W? Must all these types by CopyConstructibles?
What the library can control at compile time?
E.g. would the following compile ?
using foo = pair<int, string>;
using bar = pair<string, float>;
int baz(int, float);
foo a;
bar b;
//...
auto x = fit::by(overload(std::mem_fn(&foo::first, std::mem_fn(&bar::second), baz)(a, b);
``
Variadic signatures are difficult to follow. Giving a specific case will surely help
by :: ( (T1->U1 T2->U2) (V1 V2 -> W) ) -> ((X1 X2) -> W)
requires convertible<Xi, Ti> && convertible<Ui, Vi>
Could the functions be only movable?
Is the result type of the function copyable, movable, .... can be stored statically at compile time, and with the help of which macro?
I find it useful to have a FindXXX.cmake module for easily adding a library as a dependency in a CMake project. If you are interested in adding this, you can look at Hana's.
Some design rational would be welcome
always_ref(v)
could be equivalent to always(ref(v))
with an specialization for
template<class T>
always(reference_wrapper<T> value);
I would suggest first how the user can use the library when it doesn't need to statically initialize at compile time and only then show when it is useful to do it, the current limitation of the language C++11/C++14 and how Fit solves the issue.
Hello,
First of all, thanks for your library. Functional Programming with C++ is possible thanks to your work.
I have played with your Fit library and encounter a little problem
Let say I define the following filter_ method.
struct filter_ {
template<class L, class F>
L operator()(F f, L l) const {
L result;
for (auto& item : l)
if (f(item))
result.push_back(item);
return result;
}
};
I can use it with partial
auto filter = fit::partial(filter_());
In order to some filtering:
auto odd = fit::_1 % 2;
assert(filter(odd)(std::list<int>({1, 2, 3, 4, 5})) == {1, 3, 5});
But if I want to reuse my filter_ method with fit::pipable, I have to rewrite it just to exchange the order of the parameters:
// do not compile because of params that are not in expected order (list first, method second)
std::list<int>({1, 2, 3, 4, 5}) | fit::pipable(filter_())(odd);
Do I miss something ? Is it possible to adapt fit::pipable so that we can use it with same function object as fit::partial, fit::fuse ...
Have a nice day
Bertrand
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.