├── .clang_complete ├── .gitignore ├── lib ├── lambda.hpp └── lambda │ ├── core │ ├── macros.hpp │ ├── monad.hpp │ ├── flip.hpp │ ├── bind.hpp │ ├── compose.hpp │ ├── maybe.hpp │ ├── curried.hpp │ ├── display.hpp │ ├── apply.hpp │ ├── dollar.hpp │ ├── show.hpp │ ├── type_traits.hpp │ ├── invoke.hpp │ ├── function_traits.hpp │ └── curry.hpp │ ├── core.hpp │ ├── stream │ ├── generator.hpp │ ├── collect.hpp │ ├── pipe.hpp │ ├── fold.hpp │ ├── map.hpp │ ├── filter.hpp │ ├── chain.hpp │ ├── drop.hpp │ ├── ints.hpp │ ├── stream.hpp │ └── take.hpp │ └── stream.hpp ├── test ├── test_show.cpp ├── test_dollar.cpp ├── test_maybe.cpp ├── test_lambda.cpp ├── CMakeLists.txt ├── test_curry.cpp ├── test_stream.cpp └── test_bind.cpp ├── .gitmodules ├── bench ├── bench_lambda.cpp └── CMakeLists.txt ├── demo ├── CMakeLists.txt ├── problem.hpp └── euler.cpp ├── CMakeLists.txt ├── README.md ├── LICENSE ├── .travis.yml └── Vagrantfile /.clang_complete: -------------------------------------------------------------------------------- 1 | -Ilib 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | build/ 3 | .vagrant 4 | -------------------------------------------------------------------------------- /lib/lambda.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "lambda/core.hpp" 5 | -------------------------------------------------------------------------------- /lib/lambda/core/macros.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define let const auto 5 | 6 | #define REQUIRE_CONCEPT(...) std::enable_if_t<(__VA_ARGS__), int> = 0 7 | -------------------------------------------------------------------------------- /test/test_show.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "gmock/gmock.h" 3 | #include "lambda.hpp" 4 | 5 | using namespace lambda; 6 | using namespace lambda::factory; 7 | 8 | TEST(lambda, show) { ASSERT_EQ("[1, 2, 3, 4]", show(vector(1, 2, 3, 4))); } 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/googletest"] 2 | path = vendor/googletest 3 | url = https://github.com/google/googletest.git 4 | [submodule "vendor/benchmark"] 5 | path = vendor/benchmark 6 | url = https://github.com/google/benchmark.git 7 | -------------------------------------------------------------------------------- /lib/lambda/core/monad.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "maybe.hpp" 5 | 6 | namespace lambda { 7 | namespace monad { 8 | 9 | template 10 | auto operator>>(const Maybe &m, F &&f) { 11 | return m ? some(f(*m)) : none; 12 | } 13 | 14 | } // monad 15 | } // lambda 16 | -------------------------------------------------------------------------------- /lib/lambda/core/flip.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | namespace lambda { 7 | 8 | template 9 | auto flip(F f) { 10 | return [f](auto &&b, auto &&a) { 11 | return f(std::forward(a), std::forward(b)); 12 | }; 13 | } 14 | 15 | } /* lambda */ 16 | -------------------------------------------------------------------------------- /lib/lambda/core/bind.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "invoke.hpp" 5 | 6 | namespace lambda { 7 | 8 | template 9 | auto bind(Fn fn, Ts &&... ts) { 10 | return 11 | [fn, ts...](auto &&... ps) { return invoke(fn, ts..., std::forward(ps)...); }; 12 | } 13 | 14 | } /* lambda */ 15 | -------------------------------------------------------------------------------- /test/test_dollar.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "gmock/gmock.h" 3 | #include "lambda.hpp" 4 | 5 | using namespace lambda; 6 | using namespace lambda::factory; 7 | 8 | TEST(lambda, dollar) { 9 | ASSERT_EQ(12345, id(12345)); 10 | 11 | ASSERT_EQ(array(1, 2, 3, 4), array(1, 2, 3, 4)); 12 | ASSERT_EQ(vector(1, 2, 3, 4), vector(1, 2, 3, 4)); 13 | } 14 | -------------------------------------------------------------------------------- /lib/lambda/core/compose.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "type_traits.hpp" 5 | 6 | namespace lambda { 7 | 8 | // Note: (library fundamentals TS) 9 | 10 | template 11 | auto compose(F f, G g) { 12 | return [f, g](auto &&... ps) { return f(g(std::forward(ps)...)); }; 13 | } 14 | 15 | } /* lambda */ 16 | -------------------------------------------------------------------------------- /lib/lambda/core/maybe.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | namespace lambda { 7 | 8 | template 9 | using Maybe = std::experimental::optional; 10 | 11 | template 12 | constexpr auto some(T value) { 13 | return Maybe::type>(std::move(value)); 14 | } 15 | 16 | constexpr auto none = std::experimental::nullopt; 17 | 18 | } /* lambda */ 19 | -------------------------------------------------------------------------------- /test/test_maybe.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "gmock/gmock.h" 3 | #include "lambda.hpp" 4 | 5 | using namespace lambda; 6 | using namespace lambda::monad; 7 | 8 | auto id_m(int n) { return n; } 9 | auto id_s(int n) { return std::to_string(n); } 10 | 11 | TEST(lambda, maybe) { 12 | let num = some(1024); 13 | ASSERT_TRUE(bool(num)); 14 | 15 | let n = num >> id_m >> id_s >> ([](auto s) { return s + "!"; }); 16 | 17 | display << n << 1 << "\n"; 18 | 19 | ASSERT_EQ("1024!", *n); 20 | } 21 | -------------------------------------------------------------------------------- /lib/lambda/core.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "core/type_traits.hpp" 5 | 6 | #include "core/apply.hpp" 7 | #include "core/invoke.hpp" 8 | 9 | #include "core/bind.hpp" 10 | #include "core/compose.hpp" 11 | #include "core/curry.hpp" 12 | #include "core/flip.hpp" 13 | 14 | #include "core/macros.hpp" 15 | #include "core/maybe.hpp" 16 | 17 | #include "core/display.hpp" 18 | #include "core/monad.hpp" 19 | #include "core/show.hpp" 20 | 21 | #include "core/curried.hpp" 22 | 23 | #include "core/dollar.hpp" 24 | -------------------------------------------------------------------------------- /bench/bench_lambda.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | using namespace lambda; 8 | using namespace lambda::streams; 9 | 10 | class LambdaPerf : public benchmark::Fixture {}; 11 | 12 | BENCHMARK_F(LambdaPerf, Streams)(benchmark::State &state) { 13 | while (state.KeepRunning()) { 14 | let solution = ints(0, 1000) | filter(multipleOf(3) || multipleOf(5)) | sum; 15 | benchmark::DoNotOptimize(solution); 16 | } 17 | } 18 | 19 | BENCHMARK_MAIN(); 20 | -------------------------------------------------------------------------------- /lib/lambda/stream/generator.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "stream.hpp" 5 | 6 | namespace lambda { 7 | namespace streams { 8 | 9 | template 10 | class Generator : public Stream { 11 | G gen; 12 | 13 | public: 14 | using Type = decltype(gen()); 15 | 16 | explicit Generator(G gen) : gen(std::move(gen)) {} 17 | 18 | Maybe next() { return some(gen()); } 19 | }; 20 | 21 | template 22 | auto generator(G gen) { 23 | return Generator{gen}; 24 | } 25 | 26 | } /* streams */ 27 | } /* lambda */ 28 | -------------------------------------------------------------------------------- /demo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lib 5 | ${CMAKE_CURRENT_SOURCE_DIR}/../vendor/range/include) 6 | 7 | set(SRC ${CMAKE_CURRENT_SOURCE_DIR}/euler.cpp) 8 | 9 | add_executable(demo_lambda ${SRC}) 10 | 11 | target_link_libraries(demo_lambda) 12 | 13 | add_custom_target(demo 14 | COMMAND ${CMAKE_CURRENT_BINARY_DIR}/demo_lambda 15 | COMMENT "Run demo!" 16 | USES_TERMINAL 17 | DEPENDS demo_lambda) 18 | -------------------------------------------------------------------------------- /bench/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | include_directories(${GTEST_INCLUDE_DIRS} 5 | ${CMAKE_CURRENT_SOURCE_DIR}/../lib) 6 | 7 | set(BENCHMARKS ${CMAKE_CURRENT_SOURCE_DIR}/bench_lambda.cpp) 8 | 9 | add_executable(bench_lambda ${BENCHMARKS}) 10 | 11 | target_link_libraries(bench_lambda benchmark) 12 | 13 | add_custom_target(perf 14 | COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bench_lambda 15 | COMMENT "Build & Run Benchmarks" 16 | USES_TERMINAL 17 | DEPENDS bench_lambda) 18 | -------------------------------------------------------------------------------- /lib/lambda/core/curried.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "curry.hpp" 5 | 6 | namespace lambda { 7 | 8 | // Arithmetic operations 9 | 10 | let plus = curry(std::plus<>{}); 11 | let minus = curry(std::minus<>{}); 12 | let multiplies = curry(std::multiplies<>{}); 13 | let divides = curry(std::divides<>{}); 14 | let modulus = curry(std::modulus<>{}); 15 | let negate = curry(std::negate<>{}); 16 | 17 | // Comparisons 18 | 19 | let less = curry(flip(std::less<>{})); 20 | 21 | // Miscellaneous 22 | 23 | let multipleOf = curry(flip([](auto x, auto y) { return x % y == 0; })); 24 | let even = multipleOf(2); 25 | 26 | } /* lambda */ 27 | -------------------------------------------------------------------------------- /lib/lambda/core/display.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "show.hpp" 5 | #include 6 | 7 | namespace lambda { 8 | 9 | class Display { 10 | public: 11 | static Display get() { 12 | static Display p; 13 | return p; 14 | } 15 | 16 | Display() = default; 17 | 18 | Display &operator<<(std::string s) { 19 | std::cout << s; 20 | return *this; 21 | } 22 | }; 23 | 24 | static auto display = Display::get(); 25 | 26 | template 27 | Display &operator<<(Display &display, const T value) { 28 | display << show(value); 29 | return display; 30 | } 31 | 32 | } /* lambda */ 33 | -------------------------------------------------------------------------------- /lib/lambda/core/apply.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "invoke.hpp" 5 | 6 | #include 7 | #include 8 | 9 | namespace lambda { 10 | 11 | namespace detail { 12 | template 13 | constexpr auto apply(F &&f, Tuple &&t, std::index_sequence /*unused*/) { 14 | return invoke(std::forward(f), std::get(std::forward(t))...); 15 | } 16 | } 17 | 18 | template 19 | constexpr auto apply(F &&f, Tuple &&t) { 20 | return detail::apply(std::forward(f), std::forward(t), 21 | std::make_index_sequence>{}>{}); 22 | } 23 | 24 | } /* lambda */ 25 | -------------------------------------------------------------------------------- /lib/lambda/stream.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "core.hpp" 5 | 6 | #include "stream/generator.hpp" 7 | #include "stream/ints.hpp" 8 | #include "stream/pipe.hpp" 9 | #include "stream/stream.hpp" 10 | 11 | #include "stream/chain.hpp" 12 | #include "stream/drop.hpp" 13 | #include "stream/filter.hpp" 14 | #include "stream/map.hpp" 15 | #include "stream/take.hpp" 16 | 17 | #include "stream/collect.hpp" 18 | #include "stream/fold.hpp" 19 | 20 | // 21 | // TODO(jtomschroeder): 22 | // - max: (fold?) 23 | // - drop (change to 'skip') 24 | // - list comprehension 25 | // - stream -> iter(): useable with for-range loop 26 | // - reversable streams 27 | // - chain-able streams 28 | // - collect() 29 | // 30 | -------------------------------------------------------------------------------- /lib/lambda/stream/collect.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "lambda.hpp" 5 | 6 | namespace lambda { 7 | namespace streams { 8 | 9 | template