Relude Standard Library for ReasonML
repository·main·Indexed 42 days ago
https://github.com/reazen/reludeAn alternative standard library (prelude) for ReasonML and OCaml, optimized for compilation to JavaScript via Melange. Relude provides typeclass-driven abstractions (such as Monad, Applicative, and Traversable), an IO monad for effect management, and monad transformers like OptionT, ResultT, and StateT. It follows significant-data-last semantics using the |> pipe operator and offers a robust set of utility functions for common data types.
What's inside Relude
- Relude is a standard library replacement (prelude) for ReasonML and OCaml. It is written in ReasonML and is designed to be compiled to JavaScript using the Melange compiler. It serves as a more robust and feature-complete alternative to the default standard libraries in these ecosystems.
What is Relude?
mainRelude is a standard library for ReasonML inspired by functional programming preludes like Haskell, Purescript, Elm, and Scala (cats/scalaz). It is designed to provide powerful typeclass-style abstractions alongside practical utilities for everyday application-level work on JavaScript-based platforms (Browser and Node.js).
Key characteristics:
- Typeclass-driven: Uses abstractions like
Applicative,Monad, andTraversable. - Opinionated: Follows JavaScript/Scala-style naming conventions (camelCase/TitleCase) rather than OCaml's snake_case.
- Pipe Operator: Standardizes on the
|>pipe operator. - Compatibility: Uses core typeclass interfaces from the
mel-bastetlibrary to ensure interoperability with other libraries using the same signatures.
- Typeclass-driven: Uses abstractions like
Why Relude lacks interface (.rei) files
mainRelude does not provide
.reifiles because it relies heavily on the ReasonML/OCaml module include capability.Many Relude typeclasses use extension modules that are
include'd into your host module. This automatically adds utility functions, operators, and extension modules to your module based on the typeclass instances you create. Because these functions are added dynamically via inclusion, maintaining static.reifiles that accurately reflect all automatically added functions while providing proper documentation and type annotations is currently unfeasible.Extend modules using Typeclass Extensions
mainRelude uses Typeclass Extensions to provide high-level functionality for free. When you implement a fundamental typeclass (like
FUNCTOR,APPLY,APPLICATIVE,ALT, orMONAD), you can use Relude'sExtensionmodule functors to derive complex functions (likemap2,traverse, orfoldLeft) automatically.To use this pattern, you typically:
- Define your data type.
- Provide instances for the required typeclass signatures.
- Use the
includemechanism to add the correspondingExtensionmodules directly to your module.
Use Relude utility functions and modules
mainRelude provides a comprehensive set of low-level utility functions for common data types to replace the need for
Beltor OCaml stdlib APIs. It also includes specialized modules and types for application development.Supported Data Types include:
list('a)array('a)option('a)Belt.Result.t('a, 'e)
Specialized Utility Modules/Types:
AsyncDataandAsyncResultDecimalHListandHMapListZipperValidation
Use `*By` functions as an alternative to first-class modules
mainBecause ReasonML/OCaml lacks implicit typeclass resolution (ad-hoc polymorphism), Relude often requires passing a first-class module to functions. To simplify this, Relude provides higher-order functions with a
Bysuffix.Instead of manually creating a module that conforms to a typeclass signature (e.g., a
SHOWmodule) and passing it to a function likeshow, you can use theshowByvariant, which accepts a simple function (e.g.,'a => string) instead of a full module.Common patterns:
showByinstead ofshow(requires a function instead of aSHOWmodule).eqByinstead ofeq(requires a comparison function instead of anEQmodule).compareByinstead ofcompare.
Use the pipe operator (|>) with significant-data-last semantics
mainRelude follows significant-data-last (or pipe last) semantics. Instead of using the
->operator (common in Belt), you should use the|>operator to thread data through functions.How it works:
|>does not strictly thread a value into the last argument; it passes the value into the next unfilled argument of the function. This allows you to partially apply arguments and then feed the 'significant data' into the final argument.Benefits:
- Works in native OCaml without requiring a PPX.
- Enables natural partial application and composition.
- Aligns with other functional programming ecosystems.
Understand the relationship between Relude and Belt/OCaml stdlib
mainRelude is designed to augment existing types from
Beltand the OCaml standard library. When using Relude, you will encounter three patterns:- Aliasing: Relude may alias types from
Beltor the OCaml stdlib to provide a consistent interface. - Augmentation: Relude modules may provide additional utility functions for existing
Beltor OCaml types. - New Types: Relude defines its own unique types and modules (e.g.,
Relude.AsyncResult,Relude.ReaderT) that do not exist in the standard libraries.
- Aliasing: Relude may alias types from
Extend functionality using Typeclasses
mainRelude leverages typeclass-style abstractions to provide extra functionality to your modules automatically. If you implement a standard typeclass module type (such as those from
Bastet.Interface), you canincludea wide variety of extension functions and infix operators for free.Instead of manually implementing functions like
map2,flatten,length, ortoArrayfor your custom types, you can implement the corresponding typeclass (e.g.,MONAD), and Relude will provide these operations consistently and predictably.Perform a local dry run of the opam publishing process
mainTo verify that the package is ready for publishing without actually submitting it, you can perform a local validation. This involves installing the
opam-publishplugin, verifying metadata, checking for required fields, and ensuring the git state is valid.# Install opam-publish plugin opam install opam-publish # Test package metadata opam show --raw . # Validate required fields grep -q "^homepage:" relude.opam && grep -q "^bug-reports:" relude.opam && grep -q "^synopsis:" relude.opam && echo "✅ Required fields present" # Check git state git rev-parse --verify HEADLocate utility functions in Relude
mainRelude organizes utility functions within top-level modules corresponding to the data type they operate on.
- For a specific type: Look in
Relude.<Type>(e.g.,Relude.Optionforoption('a)orRelude.Stringforstring). - For specialized type combinations: Look in nested modules (e.g.,
Relude.List.Stringfor functions operating onlist(string)).
- For a specific type: Look in
Publish Relude manually to Opam
mainIf automated publishing is unavailable, you can publish Relude to the opam repository manually. You must first clone the repository and checkout the specific release tag corresponding to the version you wish to publish.
# Clone the repository and checkout the release tag git clone https://github.com/reazen/relude.git cd relude git checkout v<version> # Publish to opam opam publish --tag=v<version> .