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, e.g. the ocaml-rs package makes this pretty visible: https://github.com/zshipko/ocaml-rs/blob/master/examples/rus... . (I have not used either of these projects.)
Maybe the GC would be less of a problem if we didn't want to have the best possible performance as well.
It's great that this allows passing Rust structs both as ForeignPtr and as native records with marshalling!
Some questions/ideas:
- Is there a way to generate #[hsrs::data_type] bindings for Rust library types, or do you need to create custom wrapper types for them?
- It seems like all #[hsrs::function]s are translated to return IO (since Rust functions can do arbitrary side effects). It would be great if you could (unsafely) mark functions as pure, to get pure Haskell functions without having to wrap them in unsafePerformIO.
- Both Haskell and Rust have HM type systems, so I wonder if you could also translate type classes from Rust to Haskell.
> - Is there a way to generate #[hsrs::data_type] bindings for Rust library types, or do you need to create custom wrapper types for them?
At the moment, no. I'll ad this to the list of features for 0.2, totally slipped my mind, and if I remember correctly, both napi-rs and pyo3 have support for this.
> - It seems like all #[hsrs::function]s are translated to return IO (since Rust functions can do arbitrary side effects). It would be great if you could (unsafely) mark functions as pure, to get pure Haskell functions without having to wrap them in unsafePerformIO.
I did think through this a little bit and couldn't find a good way to implement this so decided to delay it until the next release, until I come up with some better ideas.
I wanted some sort of automated mechanism to determine purity, but that, obviously, doesn't exist in Rust. There _are_ some ways to approach this -- `const fn` are pure (I think), and it would be cool if I added support for https://github.com/creusot-rs/creusot. I was thinking of walking down the AST of a function to automatically infer purity, but that seems like a whole other, order-of-magnitude larger project. I'm still not sure what to do about this (bar a simple annotation), but I'll land something for 0.2. https://github.com/harmont-dev/hsrs/issues/1
> - Both Haskell and Rust have HM type systems, so I wonder if you could also translate type classes from Rust to Haskell.
Yes!! I do think that would be quite neat and I spent a little bit of time thinking through it, but I couldn't really come up with a great use-case (at least for my needs) that justified the necessity of this feature. This _might_ (probably won't) land 0.2, but it's definitely something I'm thinking about. One of the big problems that makes this quite non-trivial is monomorphization -- it's unclear what kind of specializations of a particular generic function you want in Rust. Trait objects _should_ be able to work, but I still haven't figured out the details of all of that. https://github.com/harmont-dev/hsrs/issues/2
I think purity is something the programmer just has to annotate themselves. Any boundary between languages with different type system guarantees will always have this kind of friction - Rust to C/C++ FFI also has to deal with ownership, lifetimes and aliasing manually.
Regarding type classes, monomorphisation indeed seems like a difficult obstacle for polymorphic function. But just translating type classes and impls might not be as difficult? So going from:
trait Foo {
fn foo(&self);
}
impl Foo for Bar {
fn foo(&self) {...}
}
to
class Foo a where
foo :: a -> IO ()
instance Foo Bar where
foo :: Bar -> IO ()
foo self = ...
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, e.g. the ocaml-rs package makes this pretty visible: https://github.com/zshipko/ocaml-rs/blob/master/examples/rus... . (I have not used either of these projects.)
Maybe the GC would be less of a problem if we didn't want to have the best possible performance as well.
Oh wow, that does seem quite painful. That crate reminds me of how JSC' internal bindings work:
```cpp JSC_DEFINE_HOST_FUNCTION(jsMyFunction, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)) { JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); ... ```
kind of the same thing, seems like -- passing data around to be managed by the GC.
It's great that this allows passing Rust structs both as ForeignPtr and as native records with marshalling!
Some questions/ideas:
- Is there a way to generate #[hsrs::data_type] bindings for Rust library types, or do you need to create custom wrapper types for them?
- It seems like all #[hsrs::function]s are translated to return IO (since Rust functions can do arbitrary side effects). It would be great if you could (unsafely) mark functions as pure, to get pure Haskell functions without having to wrap them in unsafePerformIO.
- Both Haskell and Rust have HM type systems, so I wonder if you could also translate type classes from Rust to Haskell.
> - Is there a way to generate #[hsrs::data_type] bindings for Rust library types, or do you need to create custom wrapper types for them?
At the moment, no. I'll ad this to the list of features for 0.2, totally slipped my mind, and if I remember correctly, both napi-rs and pyo3 have support for this.
> - It seems like all #[hsrs::function]s are translated to return IO (since Rust functions can do arbitrary side effects). It would be great if you could (unsafely) mark functions as pure, to get pure Haskell functions without having to wrap them in unsafePerformIO.
I did think through this a little bit and couldn't find a good way to implement this so decided to delay it until the next release, until I come up with some better ideas.
I wanted some sort of automated mechanism to determine purity, but that, obviously, doesn't exist in Rust. There _are_ some ways to approach this -- `const fn` are pure (I think), and it would be cool if I added support for https://github.com/creusot-rs/creusot. I was thinking of walking down the AST of a function to automatically infer purity, but that seems like a whole other, order-of-magnitude larger project. I'm still not sure what to do about this (bar a simple annotation), but I'll land something for 0.2. https://github.com/harmont-dev/hsrs/issues/1
> - Both Haskell and Rust have HM type systems, so I wonder if you could also translate type classes from Rust to Haskell.
Yes!! I do think that would be quite neat and I spent a little bit of time thinking through it, but I couldn't really come up with a great use-case (at least for my needs) that justified the necessity of this feature. This _might_ (probably won't) land 0.2, but it's definitely something I'm thinking about. One of the big problems that makes this quite non-trivial is monomorphization -- it's unclear what kind of specializations of a particular generic function you want in Rust. Trait objects _should_ be able to work, but I still haven't figured out the details of all of that. https://github.com/harmont-dev/hsrs/issues/2
Thank you for the detailed answers!
I think purity is something the programmer just has to annotate themselves. Any boundary between languages with different type system guarantees will always have this kind of friction - Rust to C/C++ FFI also has to deal with ownership, lifetimes and aliasing manually.
Regarding type classes, monomorphisation indeed seems like a difficult obstacle for polymorphic function. But just translating type classes and impls might not be as difficult? So going from:
toReally cool nice job!
With more and more ecosystem libraries being written in Rust (and a Python wrapper) could this be a way to expand the Haskell ecosystem?
Maybe!