[Tick] Universal quantified concepts/traits
Hi,
I'm trying to represent the concept of a mathematical Functor (as in
Haskell) with Concept Lite. Here is what I want to express:
A Functor W is a type constructor for wrappers of another type T
providing a
function map taking a function (T) -> U and a W<T> and returning a W<U>.
Here is how I think that could be done with Concept Lite. If I
understand the proposal correctly we need to add the type T and the
function parameter to the concept.
concept Functor
Ok, I think I understand what you are aksing for. This how I would approach
the problem using Tick. It does require defining different traits to get
there(I am not sure how it could be done all in one take). First, I would
define `is_callable` that checks if a function is called with `T` and returns
`U`:
TICK_TRAIT(is_callable)
{
template
Le 16/12/14 22:53, paul Fultz a écrit :
Ok, I think I understand what you are aksing for. This how I would approach the problem using Tick. It does require defining different traits to get there(I am not sure how it could be done all in one take). First, I would define `is_callable` that checks if a function is called with `T` and returns `U`:
TICK_TRAIT(is_callable) { template
auto requires_(F&& f, T&& t, U&&) -> tick::valid< decltype(returns<U>(f(std::forward<T>(t)))) >; }; Next I would write a trait that checks if the two types, `Wt` and `Wu`, are mapped like `W<T> -> W<U>` and that the function takes `T` and returns `U`:
template
struct is_mapped : std::false_type {}; template class W, class T, class U, class F> struct is_mapped
: is_callable {}; And then I would write the `is_functor` to call the `map` function and check that it returns a mapped type:
TICK_TRAIT(is_functor) { template
auto requires_(F&& f, Wt&& wt) -> tick::valid< decltype(returns ( map(f, std::forward<Wt>(wt)) )) >; }; Does that make sense? Is this what you are asking for?
No, this trait has two parameters F and Wt. I'm looking for a trait with a single parameter W, the type constructor. Maybe I'm looking for a thing that should not exists ;-)
But this is not exactly what I want to conceptualize. The wrapped type T and the function F should be universally quantified, that is, the concept concerns only the type constructor W: Functor<W>.
I have a problem introducing the universal quantification of T and F. I don't know how to do it without using again a template.
concept Functor<typename W> = template
// universal quantification on T and F requires { using WT = ApplyType ; using U = ResultType ; using WU = ApplyType ; Function && requires (F f, WT wt) { WU { map(f, wt) }; } } }; But this is not valid code, isn't it.
Is there something wrong with this kind of concepts? What would be the best way to conceptualize this kind of concepts with the Tick library ?
Vicente
Le 17/12/14 07:20, Vicente J. Botet Escriba a écrit :
Le 16/12/14 22:53, paul Fultz a écrit :
Ok, I think I understand what you are aksing for. This how I would approach the problem using Tick. It does require defining different traits to get there(I am not sure how it could be done all in one take). First, I would define `is_callable` that checks if a function is called with `T` and returns `U`:
TICK_TRAIT(is_callable) { template
auto requires_(F&& f, T&& t, U&&) -> tick::valid< decltype(returns<U>(f(std::forward<T>(t)))) >; }; Next I would write a trait that checks if the two types, `Wt` and `Wu`, are mapped like `W<T> -> W<U>` and that the function takes `T` and returns `U`:
template
struct is_mapped : std::false_type {}; template class W, class T, class U, class F> struct is_mapped
: is_callable {}; And then I would write the `is_functor` to call the `map` function and check that it returns a mapped type:
TICK_TRAIT(is_functor) { template
auto requires_(F&& f, Wt&& wt) -> tick::valid< decltype(returns ( map(f, std::forward<Wt>(wt)) )) >; }; Does that make sense? Is this what you are asking for?
No, this trait has two parameters F and Wt. I'm looking for a trait with a single parameter W, the type constructor. Maybe I'm looking for a thing that should not exists ;-)
This SO question presents the same context. http://stackoverflow.com/questions/23659382/specifying-a-concept-for-a-type-... HTH, Vicente
No, this trait has two parameters F and Wt. I'm looking for a trait with a single parameter W, the type constructor.
Ok I see, you mean that W is a templates.
This SO question presents the same context.
Well that is one limitation. However, template members could be solved
either
by SFINAE-friendly lift operator or with reflection. However, what you are
trying to achieve is very difficult in C++ mainly due to template
specialization, function overloading, and substitution failure. Say we had a
simple function foo:
template<class T>
U foo(T);
Now, `foo` takes a T and returns U some other type. This is simple for the
compiler to follow, however, `foo` could return a type from a metafunction
like this:
template<class T>
typename some_metafunction<T>::type foo(T);
So with this, the compiler now has to trace each and every type `T`. Now
even
if thats possible, it doesn't even completely solve the problem. Next thing
is
the `w` template could have a constraint that only works for integrals:
template
Le 06/01/15 19:48, pfultz2 a écrit :
No, this trait has two parameters F and Wt. I'm looking for a trait with a single parameter W, the type constructor. Ok I see, you mean that W is a templates. Not necessarily. W can be a class that has a nested template class apply with one parameter. That is a type constructor.
This SO question presents the same context. Well that is one limitation. However, template members could be solved either by SFINAE-friendly lift operator or with reflection. However, what you are trying to achieve is very difficult in C++ mainly due to template specialization, function overloading, and substitution failure. Say we had a simple function foo:
template<class T> U foo(T);
Now, `foo` takes a T and returns U some other type. This is simple for the compiler to follow, however, `foo` could return a type from a metafunction like this:
template<class T> typename some_metafunction<T>::type foo(T);
So with this, the compiler now has to trace each and every type `T`. Now even if thats possible, it doesn't even completely solve the problem. Next thing is the `w` template could have a constraint that only works for integrals:
template
())>> class w; So now if `foo` takes an `int` and returns `int`, but also takes a `long` and returns `std::vector<int>` then we have a problem. The map function could work correctly and map `w<T>` to `w<U>` however trying to map `w<long>` would be a compile error. So should this be considered a functor or not? Trying to decide whether its a functor in the general sense is difficult and its much better to decide on actual concrete or dependent types.
Of course, it is really useful to check your code in the more general sense instead of relying on concrete type, so concepts can actually help solve this problem(the C++0x concepts, not the SFINAE concepts being currently proposed). So you could possibly write something like this:
template class W> concept Functor { template
W<U> fmap(F f, W<T> w); }; So the concept will ensure you are following the correct "interface", so if you have a function that will use a `Functor` like this:
template
void apply(W<T> x, F f) { fmap(f, x); } So the compiler will check that you are using a `Functor` in the template. It doesn't need to check every type(like when using SFINAE concepts). Then at instantiation time the compiler will check that the concrete types meet the requirements of the concept `Functor`.
This is exactly what I would like to be able to do :) You have resumed quite well the need and the solution using C++0x Concepts. Unfortunately Concept Lite doesn't allows to express this kind of concepts :( Best, Vicente
participants (3)
-
paul Fultz
-
pfultz2
-
Vicente J. Botet Escriba