beman.monadics is a minimal C++ library conforming to The Beman Standard.
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 | 15-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-17 | C++26-C++20 | libc++ |
| Clang | 18-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.
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.