Bridging the Gap: Introducing hsrs, a Type-Safe Haskell Bindings Generator for Rust
Integrating Rust and Haskell—two of the most powerful type systems in modern programming—is a powerful combination. However, creating the bridge between them has historically been fraught with friction. Until now, most bindings generators have lacked the rich, type-safe interfaces that developers expect from both languages.
Introducing hsrs, a type-safe Haskell Bindings Generator for Rust. Designed to feel similar to tools like pyo3 and napi-rs, hsrs aims to provide a more ergonomic and type-safe way to integrate Rust code into Haskell applications.
The Need for Type-Safe Bindings
Many developers have struggled with the lack of a tool that can automatically generate rich bindings. While tools like hs-bindgen exist, hsrs distinguishes itself by providing type-safe bindings for complex types such as Result and Maybe. This ensures that the same safety guarantees provided by Rust's type system are preserved when the code is called from Haskell, preventing common FFI (Foreign Function Interface) interface errors.
Key Features and Architecture
Hsrs leverages Rust's procedural macros to allow developers to mark functions and data types for export. By doing so, it generates the necessary glue code to allow Haskell to interact with Rust structs and functions seamlessly.
Handling Data Types
One of the most significant advantages of hsrs hsrs is its ability to handle Rust structs as either ForeignPtr (for reference-based interaction) or as native Haskell records with full marshalling. This flexibility allows developers to choose the performance trade-off between keeping data in Rust-land and keeping it's own Haskell-land.
Function Mapping
Currently, the tool translates Rust functions marked with #[hsrs::function] into Haskell functions that return IO actions. This is a necessary design choice because Rust functions can perform arbitrary side effects, and Haskell's purity is maintained by wrapping these calls in the IO monad.
Community Insights and Future Directions
The community reaction to the community reaction to the_flux suggests that the GC (Garbage Collector) interaction between Haskell's GC and Rust's ownership model is a primary point of friction. As noted by user @_flux:
It would be so nice if these "well typed languages" would be able to interact better with each other. Alas, the GC will probably cause some friction... Maybe the GC would be less of a problem if we didn't want to have the best possible performance as well.
Despite these challenges, this tool opens up the possibility of expanding the Haskell ecosystem by leveraging libraries written in Rust, which is currently seeing a massive surge in ecosystem growth.
Potential Enhancements
Based on feedback from the community, several areas for future improvement have been identified:
Pure Function Marking: The ability to mark certain Rust functions as pure (unsafely) to avoid wrapping them in
unsafePerformIOand obtain pure Haskell functions.Trait Translation: Since both languages share a Hindley-Milner (HM) type system, there is potential to translate Rust traits into Haskell type classes, providing a deeper level of polymorphic integration.
External Library Integration: Improving the ability to generate
#[hsrs::data_type]bindings for types from external Rust libraries without requiring custom wrapper types.
By providing a more ergonomic bridge, hsrs allows developers to leverage the performance and safety of Rust while maintaining the high-level abstractions of Haskell.