Functional C++ map combinator using auto

functional programming in c++: how to improve your c++ programs using functional techniques
c++ functional
manning functional programming
functional programming in c++ goodreads
c++ lambda function as argument
functional library
modern c++ lambda
pure functional c++

I'm trying to use fancy -std=c++14 features to implement the "map" combinator you see in functional languages (not to be confused with std::map). My ultimate goal is to write a "facade pattern" header for functional programming that allows me to forget about side effects and iterators most of the time. I found a post by a like-minded individual at https://gist.github.com/phatak-dev/766eccf8c72484ad623b . Madhukara's version of map looks like

template <typename Collection,typename unop>
  Collection map(Collection col,unop op) {
  std::transform(col.begin(),col.end(),col.begin(),op);
  return col;
}

It seems to work perfectly as long as you don't ask for something silly, but the return type has to be the same as the input collection. My attempt to generalize to having domain and range of different types is as follows:

template <typename Collection, typename function> 
auto map(function f, Collection c)  {
  auto result;
  std::transform(c.begin(),c.end(),result.begin(),f);
  return result;
}

This doesn't compile, but hopefully it's clear to someone what I'm trying to do... I want to initialize an empty same-type-of-container-as-c of output-type-of-f's, then put the f(c[i])s in it. The compiler complains that the declaration of 'auto result' has no initializer, but I don't know how to ask for an empty whatever of whatevers. Is there a way to tweak that line to make it do what I'm trying to do? I've never tried to do anything this exotic with auto before, so any additional suggestions are welcome.

Thanks!

John

Edit: here's a hopefully-sensical example use:

auto first_letter = [](string s)  { return s[0]; }
vector<string> words; 
words.push_back("hello"); words.push_back("world");
vector<char> first_letters = map(first_letter, words); // {'h','w'}

Edit 2: Here's another approach that uses a heavyweight "streams" library (not to be confused with IO streams) to implement the "iterator pattern", like Java's Streams:

http://jscheiny.github.io/Streams/

The Java approach: http://tutorials.jenkov.com/java-collections/streams.html

This streams approach allows more freedom of choice over container types (as several answerers seem to be in favor of) and lazy evaluation.


Just use boost::adaptors::tranformed:

#include <boost/range/adaptor/transformed.hpp>

template <typename Collection, typename function> 
auto map(function f, Collection c)  {
  return c | boost::adaptors::transformed(f);
}

With this range - you can create any container you want.

char first_letter(string s)  { return s[0]; }
vector<string> words; 
words.push_back("hello"); words.push_back("world");
auto transformed_range = map(first_letter, words);
vector<char> first_letters(begin(transformed_range ), end(transformed_range ));

If you insist to have map function returning the container, not range - add one more parameter to this function template:

#include <boost/range/adaptor/transformed.hpp>

template <typename Result, typename Collection, typename function> 
auto map(function f, Collection c)  {
  auto transformed_range = c | boost::adaptors::transformed(f);
  return Result(begin(transformed_range), end(transformed_range));
}

char first_letter(string s)  { return s[0]; }
vector<string> words; 
words.push_back("hello"); words.push_back("world");
vector<char> first_letters = map<vector<char>>(first_letter, words); 

But if you really insist to have the exact behavior as you want - you must have some traits knowing how to convert collection type to other collection type with transformed value.

First - the way to have new_value_type:

template <typename Function, typename OldValueType>
struct MapToTransformedValue
{
    using type = decltype(std::declval<Function>()(std::declval<OldValueType>()));
};

The general trait:

template <typename Function, typename Container>
struct MapToTransformedContainer;

The easiest case - for std::array:

// for std::array
template <typename Function, typename OldValueType, std::size_t N> 
struct MapToTransformedContainer<Function, std::array<OldValueType, N>>
{
    using value_type = typename MapToTransformedValue<Function, OldValueType>::type;
    using type =  std::array<value_type, N>;
};

For std::vector - a little more complicated - you need to provide new allocator, for std allocators - you can use its rebind template:

// for std::vector
template <typename Function, typename OldValueType, typename OldAllocator> 
struct MapToTransformedContainer<Function, std::vector<OldValueType, OldAllocator>>
{
    using value_type = typename MapToTransformedValue<Function, OldValueType>::type;
    using allocator = typename OldAllocator::template rebind<value_type>::other;
    using type =  std::vector<value_type, allocator>;
};

So your function will look like the following:

template <typename Collection, typename function> 
auto map(function f, Collection c)  
{
    using NewCollectionType = typename MapToTransformedContainer<function, Collection>::type;
    auto transformed_range = c | boost::adaptors::transformed(f);
    return NewCollectionType (begin(transformed_range), end(transformed_range));
}

Now - your main() is as desired:

char first_letter(std::string const& s)  { return s[0]; }

int main() {
    std::vector<std::string> words; 
    words.push_back("hello"); words.push_back("world");
    auto first_letters = map(first_letter, words); 
    std::cout << first_letters[0] << std::endl;
}

Beware that for other containers where value_type consists of Key,Value pair - like std::map, std::set (and their unordered_... siblings) you must define another specialization of MapToTransformedContainer...

Functional programming in C++, In C++11 standard, meaning of auto keyword is changed. To remedy that,​function objects or lambdas are just a class with operate method. at how we can apply different combinators like map,filter etc on C++ vector. As you can see, we use auto here so that we don’t have to care about how these function objects are encoded inside the C++ types. Functional combinators on C++ vector. We are going to see how we can do functional programming by looking at how we can apply different combinators like map,filter etc on C++ vector. Though we have used vector in


I would make use of the fact that most containers have a constructor taking a pair of iterators.

#include <boost/iterator/transform_iterator.hpp>

template <typename Function, typename Collection>
struct map_to
{
    Function f;
    const Collection& c;

    template <typename T>
    operator T() &&
    {
        using std::begin; using std::end;
        return { boost::make_transform_iterator(begin(c), f)
               , boost::make_transform_iterator(end(c), f) };
    }
};

template <typename Function, typename Collection> 
map_to<Function, Collection> map(Function f, const Collection& c)
{
    return { f, c };
}

Tests:

int main()
{
    std::vector<std::string> words; 

    words.push_back("hello");
    words.push_back("world");

    auto first_letter = [](std::string s) { return s[0]; };

    std::vector<char> v = map(first_letter, words);
    std::set<char> s = map(first_letter, words);
    std::forward_list<char> f = map(first_letter, words);
}

DEMO

Study Notes: Functional Programming with C++, I have been enthused with functional programming recently. As C++ (else (​cons (f (car l)) (map f (car l)))))) Y Combinator and C++In "C++". Type Inference refers to automatic deduction of the data type of an expression in a programming language. Before C++ 11, each data type needs to be explicitly declared at compile time, limiting the values of an expression at runtime but after the new version of C++, many keywords are included which allows a programmer to leave the type deduction to the compiler itself.


Just for the fun of it, here's my go at this problem:

#include <iostream>
#include <algorithm>
#include <set>
#include <vector>

template <template<typename...> class Collection> 
struct mapper {
    template<typename function, typename T, typename... Rest>
    static auto map(function f, const Collection<T, Rest...>& c)  {
      Collection<decltype(f(*c.begin()))> result;
      std::transform(c.begin(),c.end(),std::inserter(result, result.end()),f);
      return result;
    }
};

int main()
{
    // Example 1
    std::vector<int> v{0, 1};
    auto fv = mapper<std::vector>::map([](const auto& val) { return val + 0.1f; }, v);
    for (const auto& f : fv) { std::cout << f << " "; }

    std::cout << "\n";

    // Example 2 
    std::set<float> m{1, 2, 3, 4}; 
    auto fm = mapper<std::set>::map([](const auto& val) { return static_cast<int>(val / 2.0f); }, m);
    for (const auto& f : fm) { std::cout << f << " "; }
}

Note, that this would only work as long as you are happy with default values for everything but the type parameter of the output container.

Functional and Logic Programming: 11th International Symposium, , We use the function dup that duplicates a value dup :: d -> (d,d); dup x = (x,x) The to the translation function tl to arrows using the arrows combinators (<<<, arr, loop): tl using the type Automaton [9]: newtype Automaton b c = Auto (b -> (c, Automaton b c) as a function that maps an input (in b) to an output (in c) and a  Y Combinator and C++ If one searches for ‘ Y combinator’ now, it is likely that the first hit is Paul Graham’s incubator company Y Combinator . I am not sure whether Paul likes this fact or not—as a Lisp hacker, he must like the Y combinator very much to name his company with it, but now people looking for information for the


I had the same task, and was okay with compromising on functionality if it meant reduced boilerplate.

Here's what I ended up with (may not work with containers which use more than one explicit arg or whose template args cannot be inferred trivially, but you'll agree it is clean to use).

using std::vector;

template<typename Src, typename Dst, template<class, typename ...> typename Container>
Container<Dst> fmap(Container<Src>& container, Dst(*f)(Src)) {
    Container<Dst> result;
    result.reserve(container.size());
    std::transform(container.begin(), container.end(), std::back_inserter(result), f);
    return result;
}

int main() {
    vector<int> a = {1, 2, 3};
    auto f = [](int x) -> double { return (x + 1)/2; };
    vector<double> b = fmap(a, +f);
    for (auto x: b) {
        std::cout << x << std::endl;
    }
    return 0;
}

A major requirement for me was to not make it ugly to use, and it shouldn't use boost.

Edit: This would also behave dumb (read: not compile) if you tried to pass a vector with a non-standard allocator, let's say.

Functional Programming in C++ · GitHub, /usr/bin/g++-4.9 -std=c++11 lambda.cpp Example showing the function programming ideas in. C++ 11. auto returnCol = map(col,addOne); With that in mind: diff --git Is there a way to generalize your map combinator so that the output collection does not necessarily have the same type as the input? Maps are associative containers that store elements formed by a combination of a key value and a mapped value, following a specific order. In a map, the key values are generally used to sort and uniquely identify the elements, while the mapped values store the content associated to this key.


Proceedings of the Sixth ACM SIGPLAN International Conference on , they are built into the arrow combinators, and thus hidden by the arrow Instead of maps of sequences, we could use automata that map an input to an output and a new circuit, as follows: newtype Auto b c = A (b → (c. We can generalize the types SeqMap and Auto, replacing the function type with an arrow parameter,  For example, fractions like 3/2, 4/3, 5/4 will all be returned as 1 from the map() function, despite their different actual values. So if your project requires precise calculations (e.g. voltage accurate to 3 decimal places), please consider avoiding map() and implementing the calculations manually in your code yourself.


Interactive Theorem Proving: First International Conference, ITP , is first transformed to y ∈ {x,y,z} and then proved automatically by the method auto. Hence, when using the ICF to implement some algorithm, the algorithm is first set or map is a generalized fold combinator: It applies a state-transforming function It takes a continuation condition c, a state transformer f, the set s, and the  This rules out the usual definition of a recursive function wherein a function is associated with the state of a variable and this variable's state is used in the body of the function. The Y combinator is itself a stateless function that, when applied to another stateless function, returns a recursive version of the function.


Intrinsic Currying for C++ Template Metaprograms, sal property of an updated right-fold combinator, to compose a range Considering the high profile of C++, and template metaprogramming, it is surprising that substantial Often map is named transform after the standard C++ runtime function. A fold is template <auto I> using ic = std::​integral_constant<decltype(I),I>;. Yes, you can use auto in a function declaration in C++14 (see example bellow). Though I suspect it's some sort of templating shorthand. Note the addresses of the &#039;i&#039; static variables are different between the Call that takes a functor and one that