Skip to content

KrishnaAchuthan/curry

Repository files navigation

###Support for Curry and Function Composition in C++

####What is this? Functional programming languages such as Haskell has features such as currying, function composition etc. This library is an attempt to bring such features into C++ using modern techniques available in C++14.

####Usage This is a header only library. Just include the file fn.hpp in your source code. The main function 'fn' and the related components are available inside the namespace 'curry'

####Tools needed This project uses C++ 14 language features. It is successfully compiled under MSVC 2015, Clang 3.6.0 and GCC 4.92 (using the std=c++1y switch)

####Notes #####1. Enabling currying - Global, Member, Functor and Lambda Functions as well as Member Variables.

    auto f1 = fn(foo);            //Global function.
    auto f2 = fn(&A::bar);        //Member function of a class.
    auto f3 = fn(B());            //Functor
    
    auto lambda = [](auto arg1) {
       return arg1*10.0;
    };
    auto f4 = fn(lambda);         //Lambda. Anonymous lambda works too.
    
    //Binding a member variable. Creates a one argument function.
    auto f5 = fn(&std::pair::second); 

#####2. Partial application of Functions

    //foo is a function that takes four arguments. Two are partially applied here.
    auto partially_applied = fn(foo, arg1, arg2);
    
    //The remaining two arguments are supplied here. Calls foo(arg1, arg2, arg3, arg4);
    partially_applied(arg3, arg4);

#####3. Currying of Functions

   //foo is a function that takes four arguments.
   auto curried_function = fn(foo); 
   
   auto one_arg_applied              = curried_function(arg1);
   auto some_more_applied            = one_arg_applied(arg2, arg3);
   auto the_rest_applied_and_invoked = some_more_applied(arg4);

#####4. Placeholders

   auto f1 = fn(foo);                      //foo takes four arguments.
   auto f2 = f1(_4, _1, _3, _2);           //Reorder arguments.
   auto f3 = f2(arg1, arg2, arg3, arg4);   //Calls foo(arg4, arg1, arg3, arg2)

#####5. Anonymous Placeholders

   auto f1 = fn(foo);                      //foo takes four arguments.
   auto f2 = f1(_, arg1, arg2, _);         //Some arguments are applied. It waits for more.
   
   //Remaining arguments provided. Invokes foo(arg3, arg1, arg2, arg4)
   auto f3 = f2(arg3, arg4);

#####6. Function Composition ( Using composition operator '*' )

   //foo takes four arguments
   auto f1 = fn(foo);
   
   //bar is a function that takes two arguments. It is composed in.
   auto f2 = f1(arg1, _, arg2, arg3) * bar;
   
   //Calls foo(arg1, bar(arg4, arg5), arg2, arg3)
   auto f3 = f2(arg4, arg5);

#####7. With Each ( Binding containers to values just like Monads and Applicative Functors )

   int add_three_numbers(int a, int b, int c) {
      return a + b + c;
   }

   std::vector<int> v1 = { 19,17,21 };
   std::vector<int> v2 = { 23,49 };
   std::vector<int> v3 = { 7, 13 };

   auto adder  = fn(add_three_numbers);
   auto result = adder(with_each(v1), with_each(v2), with_each(v3));

   //result will be a vector with 12 values {49, 55, 75, 81, 47, 53, 73, 79, 51, 57, 77, 83}

#####8. Maybe

   int add_three_numbers(int a, int b, int c) {
      return a + b + c;
   }

   auto value1 = maybe(10);
   auto value2 = maybe(20);
   auto value3 = maybe(30);

   auto adder  = fn(add_three_numbers);
   auto result = adder(value1, value2, value3);

   //result will be maybe_t<int>(60)

   auto value4 = maybe(10);
   auto value5 = maybe_t<int>();
   auto value6 = maybe(30);

   auto adder  = fn(add_three_numbers);
   auto result = adder(value4, value5, value6);

   //result will be maybe_t<int>() which is empty since value5 is empty
   

#####9. Pipe Operator '|'

   auto print = fn([](const std::string& str) { std::cout << str << std::endl; });
   auto world = _ + std::string("world");
   "hello " | world | print; //prints "hello world" to the console

#####10. On the fly function creation with placeholders

   auto times10 = _ * 10;
   auto result1 = times10(4.2); //result1 will be 42.0
   
   auto greaterThan42 = 42 < _;
   auto result2 = 32 | greaterThan42; //result2 will be false

#####11. Immutable list (Code inspired by Bartosz Milewski's SimpleList)

   auto lst = make_list<int>({1,2,3,4,5,6,7,8,9});
   
   auto lst2 = tail(lst); //lst2 will be [2,3,4,5,6,7,8,9]
   auto val = head(lst2); //val will be 2
   auto lst3 = 1 + lst2; //lst3 will be [1,2,3,4,5,6,7,8,9]
   
   auto is_lst_empty = empty(lst); //result will be false

   auto second_item_of_lst3 = head(tail(lst3)); //result will be 2

#####12. Higher Order Functions

   auto lst = make_list<int>({1,2,3,4,5,6,7,8,9});

   auto square = fmap(_1*_1); //on the fly function creation with curried fmap application
   auto fmap_result = square(lst); //result will be [1,2,9,16,25,36,49,64,81]

   auto sum = foldl(_+_, 0);     //curried foldl application
   auto product = foldr(_*_, 1); //curried foldr application

   auto sum_result = sum(lst);  //result will be 45
   std::cout << sum_result << std::endl;

   auto product_result = lst | product; //result will be 362880
   std::cout << product_result << std::endl;

About

Support for Currying and Function Composition in C++

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages