2019-05-13 00:46:08 +07:00
2019-05-13 01:11:22 +07:00
2018-12-08 09:46:55 +07:00
2019-05-13 02:17:32 +07:00
2019-05-13 01:34:17 +07:00
2019-01-02 10:50:25 +07:00

kari.hpp Tweet

Experimental library for currying in C++17

travis appveyor codecov language license paypal

Installation

kari.hpp is a header-only library. All you need to do is copy the headers files from headers directory into your project and include them:

#include "kari.hpp/kari.hpp"

Also, you can add the root repository directory to your cmake project:

add_subdirectory(external/kari.hpp)
target_link_libraries(your_project_target kari.hpp)

Examples

Basic currying

auto foo = [](int v1, int v2, int v3) {
  return v1 + v2 + v3;
};

auto c0 = kari::curry(foo); // currying of `foo` function
auto c1 = c0(10);           // apply to first argument
auto c2 = c1(20);           // apply to second argument
auto rr = c2(12);           // apply to third argument and call the `foo` function

// output: 42
std::cout << rr << std::endl;

Partial application of curried functions

auto foo = [](int v1, int v2, int v3, int v4) {
  return v1 + v2 + v3 + v4;
};

auto c0 = kari::curry(foo); // currying
auto c1 = c0(15, 20);       // partial application of two arguments
auto rr = c1(2, 5);         // partial application and call `foo(15,20,2,5)`

// output: 42
std::cout << rr << std::endl;

Calling nested curried functions

auto boo = [](int v1, int v2) {
  return v1 + v2;
};

auto foo = [boo](int v1, int v2) {
  return kari::curry(boo, v1 + v2);
};

auto c0 = kari::curry(foo)(38,3,1);
auto c1 = kari::curry(foo)(38,3)(1);
auto c2 = kari::curry(foo)(38)(3,1);

// output: 42,42,42
std::cout << c0 << "," << c1 << "," << c2 << std::endl;

Binding member functions and member objects

struct Foo {
  int v = 40;
  int addV(int add) {
    v += add;
    return v;
  }
} foo;

auto c0 = kari::curry(&Foo::addV);
auto c1 = kari::curry(&Foo::v);

auto r0 = c0(std::ref(foo))(2);
auto r1 = c1(foo);

// output: 42,42
std::cout << r0 << "," << r1 << std::endl;

API

namespace kari {
  template < typename F, typename... Args >
  constexpr decltype(auto) curry(F&& f, Args&&... args) const;

  template < typename F, typename... Args >
  constexpr decltype(auto) curryV(F&& f, Args&&... args) const;

  template < std::size_t N, typename F, typename... Args >
  constexpr decltype(auto) curryN(F&& f, Args&&... args) const;

  template < typename F >
  struct is_curried;

  template < typename F >
  inline constexpr bool is_curried_v = is_curried<F>::value;

  template < std::size_t N, typename F, typename... Args >
  struct curry_t {
    template < typename... As >
    constexpr decltype(auto) operator()(As&&... as) const;
  };
}

kari::curry(F&& f, Args&&... args)

Returns a curried function f or copy the function result with args arguments.


kari::curryV(F&& f, Args&&... args)

Allows carrying variadic functions.

auto c0 = kari::curryV(std::printf, "%d + %d = %d");
auto c1 = c0(37, 5);
auto c2 = c1(42);

// force calling carried variadic function
c2(); // output: 37 + 5 = 42

kari::curryN(F&& f, Args&&... args)

Allows carrying variadic functions for N arguments.

char buffer[256] = {'\0'};
auto c = kari::curryN<3>(std::snprintf, buffer, 256, "%d + %d = %d");
c(37, 5, 42);
std::cout << buffer << std::endl;  // output: 37 + 5 = 42

kari::is_curried<F>, kari::is_curried_v<F>

Checks whether F is a curried function type.

auto l = [](int v1, int v2){
  return v1 + v2;
};
auto c = curry(l);

// output: is `l` curried? no
std::cout
  << "is `l` curried? "
  << (is_curried<decltype(l)>::value ? "yes" : "no")
  << std::endl;

// output: is `c` curried? yes
std::cout
  << "is `c` curried? "
  << (is_curried_v<decltype(c)> ? "yes" : "no")
  << std::endl;

kari::curry_t::operator()(As&&... as)

Calling operator of curried function for partial application or full application. Returns a new curried function with added new arguments or copy of the function result.

int foo(int v1, int v2, int v3, int v4) {
  return v1 + v2 + v3 + v4;
}

auto c0 = kari::curry(foo); // currying
auto c1 = c0(15, 20);       // partial application
auto rr = c2(2, 5);         // function call - foo(15,20,2,5)

// output: 42
std::cout << rr << std::endl;

Free syntactic sugar

Section of operators

using namespace kari::underscore;
std::vector<int> v{1,2,3,4};

// result: 10
std::accumulate(v.begin(), v.end(), 0, _+_);

// v = 2, 3, 6, 8
std::transform(v.begin(), v.end(), v.begin(), _*2);

// v = -2,-3,-6,-8
std::transform(v.begin(), v.end(), v.begin(), -_);

Function composition

Pipe operator

using namespace kari::underscore;

auto r0 = (_*2) | (_+2) | 4; // (4 * 2) + 2 = 10
auto r1 = 4 | (_*2) | (_+2); // (4 * 2 + 2) = 10

// output: 10,10
std::cout << r0, << "," << r1 << std::endl;

Compose operator

using namespace kari::underscore;

auto r0 = (_*2) * (_+2) * 4; // (4 + 2) * 2 = 12
auto r1 = 4 * (_*2) * (_+2); // (4 * 2 + 2) = 10

// output: 12,10
std::cout << r0, << "," << r1 << std::endl;

Point-free style for Haskell maniacs

using namespace kari::underscore;

// (. (+2)) (*2) $ 10 == 24 // haskell analog
auto r0 = (_*(_+2))(_*2) * 10;

// ((+2) .) (*2) $ 10 == 22 // haskell analog
auto r1 = ((_+2)*_)(_*2) * 10;

// output: 24,22
std::cout << r0, << "," << r1 << std::endl;

License (MIT)

Description
Languages
C++ 89%
CMake 11%