Topic: Lambdas, Overloading and Pattern matching


Author: Mathias Gaunard <loufoque@gmail.com>
Date: Mon, 15 Oct 2007 23:44:29 CST
Raw View
On 14 oct, 09:40, int...@gmail.com wrote:

> It seems that it could be implemented as a library in C++0x:
>
> <snip smart recursive inheritance />
>
> template <class T>
> void foo(const T& x)
> {
>   std::string type_name =
>     match(x,
>       <>(int x)("int")
>       <>(float x)("float")
>       <>(...)("unknown")
>     );
>
> }

Very nice syntax, and nice implementation too.

>
> The above is a single example which only does pattern matching on
> single values (but then so does boost::variant), and relies on the
> presence of argument_type & result_type (but lambdas do provide that).
> However, it seems to be quite possible to extend this to handle multi-
> value patterns, and use decltype and variadic templates to decompose
> signatures of function objects when argument_type & result_type are
> not available, thus providing a fully generalised solution.

I don't really see how you can decompose signatures, could you
elaborate?


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: int19h@gmail.com
Date: Tue, 16 Oct 2007 10:25:17 CST
Raw View
On Oct 16, 9:44 am, Mathias Gaunard <loufo...@gmail.com> wrote:
> > However, it seems to be quite possible to extend this to handle multi-
> > value patterns, and use decltype and variadic templates to decompose
> > signatures of function objects when argument_type & result_type are
> > not available, thus providing a fully generalised solution.
>
> I don't really see how you can decompose signatures, could you
> elaborate?

In the absence of concepts and particularly concept_maps, we only have
to consider two possibilities: plain function pointers, and classes
with overriden operator().
Both cases can be handled by applying decltype to a variadic template
function, letting it deduce the argument types:

// definition
template <class Return, class... Args>
std::tuple<Args...> extract_args(Return(*)(Args...)); //undefined

// usage
typedef decltype(extract_args(funcptr)) argument_types;


// definition
template <class T, class Return, class... Args>
std::tuple<Args...> extract_args(Return(T::*)(Args...)); //undefined
template <class Functor>
decltype(extract_args(&Functor::operator())) extract_args(Functor); //
undefined

// usage
typedef decltype(extract_args(funcobj)) argument_types;


With concepts, this won't work, since 1) operator() can be defined in
a concept_map, and 2) address of member function introduced via
concept cannot be taken. I wonder though if concepts themselves can be
used to deduce arguments? I.e.:

template <class Functor, class... Args>
requires Callable<Functor, Args...>
std::tuple<Args...> extract_args(Functor);


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: int19h@gmail.com
Date: Sun, 14 Oct 2007 01:40:12 CST
Raw View
On Oct 9, 10:09 pm, Mathias Gaunard <loufo...@gmail.com> wrote:
> boost.variant for example allows to visit a variant type through
> overloading. This is very similar to sum types and pattern matching in
> languages like ML.
> However, this is quite verbose to write.
>
> Lambdas, in their current form, do not take overloading into account,
> and thus do not allow for nice and concise syntax to write different
> kind of code depending on the type of their argument.
> I am therefore wondering if anyone any thought of creating a new and
> nicer syntax for that kind of thing?

It seems that it could be implemented as a library in C++0x:

// definition

namespace detail
{
  template <class... Types>
  struct common_type;

  template <class T>
  struct common_type<T>
  {
    typedef T result;
  }

  template <class T1, class T2>
  struct common_type<T1, T2>
  {
    typedef decltype(true ? *static_cast<T1*>(0) :
*static_cast<T2*>(0)) result;
  };

  template <class T1, class T2, class... Types>
  struct common_type<T1, T2, Types...>
  {
    typedef typename common_type<typename common_type<T1, T2>::result,
Types...>::result result;
  };

  template <class... Patterns>
  struct matcher;

  template <>
  struct matcher<>
  {
  };

  template <class Pattern, class... Patterns>
  struct matcher<Pattern, Patterns...> : matcher<Patterns...>
  {
    Pattern pattern;

    matcher(Pattern pattern, Patterns... patterns)
      : pattern(pattern), matcher<Patterns...>(patterns...)
    {
    }

    typename Pattern::result_type operator()(Pattern::argument_type&&
arg)
    {
      return pattern(arg);
    }
  };
}

template <class T, class... Patterns>
typename detail::common_type<Patterns::result_type...>::result
match(T&& value, Patterns... patterns)
{
  detail::matcher<Patterns...>(patterns...)(value);
}


// usage

template <class T>
void foo(const T& x)
{
  std::string type_name =
    match(x,
      <>(int x)("int")
      <>(float x)("float")
      <>(...)("unknown")
    );
}

The above is a single example which only does pattern matching on
single values (but then so does boost::variant), and relies on the
presence of argument_type & result_type (but lambdas do provide that).
However, it seems to be quite possible to extend this to handle multi-
value patterns, and use decltype and variadic templates to decompose
signatures of function objects when argument_type & result_type are
not available, thus providing a fully generalised solution.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Mathias Gaunard <loufoque@gmail.com>
Date: Tue, 9 Oct 2007 12:09:13 CST
Raw View
boost.variant for example allows to visit a variant type through
overloading. This is very similar to sum types and pattern matching in
languages like ML.
However, this is quite verbose to write.

Lambdas, in their current form, do not take overloading into account,
and thus do not allow for nice and concise syntax to write different
kind of code depending on the type of their argument.
I am therefore wondering if anyone any thought of creating a new and
nicer syntax for that kind of thing?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]