beman.monadics is a Beman library that generalizes the monadic vocabulary to any type that models a "box".
Implements: Monadics operations as free functions
Status: Under development and not yet ready for production use.
This library generalizes the monadic vocabulary to any type that models a "box".
beman.monadics is distributed under the Apache License v2.0 with LLVM Exceptions.
- Free-function monadic operations
- Pipe (
|) syntax for composition - Extensible via
box_traits - Value-category preserving
- Concept-constrained APIs
- Semantics aligned with standard monadic operations
The initial operation set mirrors the C++23/C++26 monadic vocabulary:
and_thentransformor_elsetransform_error
Semantics follow std::expected / std::optional.
The goal is to validate the unifying abstraction first.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <optional>
#include <cstdlib>
#include <beman/monadics/monadics.hpp>
template <typename T>
struct beman::monadics::box_traits<std::optional<T>> {
[[nodiscard]] static constexpr auto error() noexcept { return std::nullopt; }
};
int main() {
namespace bms = beman::monadics;
const auto result =
std::optional{10}
| bms::and_then([](auto&& v) {
return std::optional{v * 2.0};
})
| bms::transform([](double v) {
return static_cast<int>(v);
})
| bms::and_then([](int) {
return std::optional<char>{}; // failure
})
| bms::or_else([] {
return std::optional{EXIT_SUCCESS};
});
return result.value_or(EXIT_FAILURE);
}std::shared_ptr can act as a box: it may contain a value or be empty. Unlike std::optional, it has no error type, so transform_error is disabled. We can still use and_then, transform, and or_else.
#include <beman/monadics/monadics.hpp>
#include <memory>
template <typename T>
struct beman::monadics::box_traits<std::shared_ptr<T>> {
[[nodiscard]] static constexpr bool has_value(const auto& box) noexcept {
return static_cast<bool>(box);
}
[[nodiscard]] static constexpr decltype(auto) value(auto&& box) noexcept {
return *std::forward<decltype(box)>(box);
}
[[nodiscard]] static constexpr auto error() noexcept { return nullptr; }
[[nodiscard]] static constexpr decltype(auto) make(auto&& value) noexcept {
return std::make_shared<T>(std::forward<decltype(value)>(value));
}
};
int main() {
namespace bms = beman::monadics;
auto ptr = std::make_shared<int>(10);
auto result =
ptr
| bms::and_then([](int v) { return std::make_shared<int>(v * 2); })
| bms::transform([](int v) { return v + 3; })
| bms::or_else([]() { return std::make_shared<int>(0); });
if (result) {
std::cout << "Result: " << *result << "\n"; // prints 23
}
return 0;
}This project requires at least the following to build:
- A C++ compiler that conforms to the C++20 standard or greater
- CMake 3.30 or later
- (Test Only) Catch2
You can disable building tests by setting CMake option BEMAN_MONADICS_BUILD_TESTS to
OFF when configuring the project.
| Compiler | Version | C++ Standards | Standard Library |
|---|---|---|---|
| GCC | 16-13 | C++26-C++20 | libstdc++ |
| GCC | 12-11 | C++23, C++20 | libstdc++ |
| Clang | 22-19 | C++26-C++20 | libstdc++, libc++ |
| Clang | 18 | C++26-C++20 | libc++ |
| Clang | 18 | C++23-C++20 | libstdc++ |
| Clang | 17 | C++26-C++20 | libc++ |
| Clang | 17 | C++20 | libstdc++ |
| AppleClang | latest | C++26-C++20 | libc++ |
| MSVC | latest | C++23 | MSVC STL |
See the Contributing Guidelines.
You can build monadics using a CMake workflow preset:
cmake --workflow --preset gcc-releaseTo list available workflow presets, you can invoke:
cmake --list-presets=workflowFor details on building beman.monadics without using a CMake preset, refer to the Contributing Guidelines.
The preferred way to install monadics is via vcpkg. To do so, after installing vcpkg
itself, you need to add support for the Beman project's vcpkg
registry by configuring a
vcpkg-configuration.json file (which monadics provides).
Then, simply run vcpkg install beman-monadics.
To install beman.monadics globally after building with the gcc-release preset, you can
run:
sudo cmake --install build/gcc-releaseAlternatively, to install to a prefix, for example /opt/beman, you can run:
sudo cmake --install build/gcc-release --prefix /opt/bemanThis will generate the following directory structure:
/opt/beman
├── include
│ └── beman
│ └── monadics
│ ├── monadics.hpp
│ └── ...
└── lib
└── cmake
└── beman.monadics
├── beman.monadics-config-version.cmake
├── beman.monadics-config.cmake
└── beman.monadics-targets.cmakeIf you installed beman.monadics to a prefix, you can specify that prefix to your CMake
project using CMAKE_PREFIX_PATH; for example, -DCMAKE_PREFIX_PATH=/opt/beman.
You need to bring in the beman.monadics package to define the beman::monadics CMake
target:
find_package(beman.monadics REQUIRED)You will then need to add beman::monadics to the link libraries of any libraries or
executables that include beman.monadics headers.
target_link_libraries(yourlib PUBLIC beman::monadics)To use beman.monadics in your C++ project,
include an appropriate beman.monadics header from your source code.
#include <beman/monadics/monadics.hpp>Note
beman.monadics headers are to be included with the beman/monadics/ prefix.
Altering include search paths to spell the include target another way (e.g.
#include <monadics.hpp>) is unsupported.