aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Grois <andi@grois.info>2023-03-23 00:00:08 +0100
committerAndreas Grois <andi@grois.info>2023-03-23 00:00:08 +0100
commit1bdd780f02b5ba57795820360d19b241cb0dd006 (patch)
tree0ae211f4eb65f0de671151b8284200116b141b90
parent206d8419e6f04146db7a49c79e0978ecfccea974 (diff)
Minor docs update and addition of one unit test.
-rw-r--r--Cargo.toml9
-rw-r--r--src/lib.rs38
2 files changed, 41 insertions, 6 deletions
diff --git a/Cargo.toml b/Cargo.toml
index eddd798..e94fbfe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,13 +1,14 @@
[package]
name = "higher-free-macro"
-version = "0.0.1"
+version = "0.1.0"
edition = "2021"
-authors = ["Andreas Grois"]
+authors = ["Andreas Grois", "stillalive studios"]
rust-version = "1.66.1"
-description = "A macro that allows to conjure a Free Monad for every Functor. This builds on the traits from the higher crate, and re-exports said crate."
+description = "A macro that creates a (naive) Free Monad type based on a user-supplied Functor. It uses the traits from the \"higher\" crate. This macro is a port of the Control.Monad.Free part of the \"free\" Haskell package by Edward Kmett."
repository = "https://github.com/soulsource/higher-free-macro"
license = "MPL-2.0+"
-keywords = ["functor", "applicative", "monad", "category-theory", "haskell"]
+keywords = ["functor", "applicative", "monad", "category-theory", "haskell", "free-monad"]
+categories = ["mathematics", "data-structures"]
[dependencies]
higher = "0.2" \ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 38651ff..565f3a0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,6 @@
//! A macro that uses the traits from the [higher] crate and generates a Free [`Monad`][higher::Monad] type for a given [`Functor`][higher::Functor].
//!
-//! This is a port of the ["free" Haskell package](https://hackage.haskell.org/package/free).
+//! This is a port of the Control.Monad.Free part of the ["free" Haskell package](https://hackage.haskell.org/package/free) by Edward Kmett.
//!
//! # What is a Free Monad?
//! A Free Monad is the left-adjoint to the Forget-Functor from the category of Monads into the category of Endofunctors.
@@ -40,6 +40,10 @@
//!
//! See the [blog post about this crate](https://www.grois.info/posts/2023-03/2023-03-11-adventures-with-free-monads-and-higher.xhtml)
//! for a more detailed explanation.
+//!
+//! # A word of warning:
+//! This crate should be considered a proof-of-concept. Its memory complexity is horrendous, and the performance of the Free Monad's [`Apply`][higher::Apply]
+//! implementation can only be described as abysmal due to its reliance on deep copies.
pub extern crate higher;
@@ -57,6 +61,12 @@ pub extern crate higher;
/// it is typically not necessary to have a fully fledged [`Monad`][higher::Monad]. In most use cases, it's enough to have
/// [`Functor`][higher::Functor] + [`Bind`][higher::Bind] + [`Pure`][higher::Pure].
///
+/// The Free Monad type is implemented recursively. It is therefore akin to a linked tree, with all the respective performance implications.
+///
+/// Furthermore, the implementation of [`Apply`][higher::Apply] creates a potentially high number of deep copies of the `self` parameter.
+/// It should therefore be avoided, unless one really needs its
+/// [tree-merging behaviour](https://www.grois.info/posts/2023-03/2023-03-11-adventures-with-free-monads-and-higher.xhtml#ugly_apply_drawing).
+///
/// # Usage
/// As stated above, the syntax to create a Free Monad is usually to call the macro with the desired Free Monad type as first,
/// and the [`Functor`][higher::Functor] it should be based on as second parameter.
@@ -330,7 +340,7 @@ macro_rules! free {
#[cfg(test)]
mod free_monad_tests{
- use higher::{Pure, Functor};
+ use higher::{Pure, Functor, Bind};
use super::free;
@@ -385,4 +395,28 @@ mod free_monad_tests{
}
}
+ #[test]
+ fn test_bind_no_lifetime(){
+ let f = FreeVec::lift_f(vec![1,2]);
+ let f = f.bind(|x| if x % 2 == 0 { FreeVec::lift_f(vec![x as f32,x as f32 + 1.0f32])} else { FreeVec::Pure(x as f32)});
+ match f {
+ FreeVec::Free(f) => {
+ match &**f {
+ [FreeVec::Pure(a),FreeVec::Free(b)] => {
+ assert_eq!(*a, 1.0f32);
+ match &***b {
+ [FreeVec::Pure(a), FreeVec::Pure(b)] => {
+ assert_eq!(*a, 2.0f32);
+ assert_eq!(*b, 3.0f32);
+ },
+ _ => unreachable!()
+ }
+ },
+ _ => unreachable!()
+ }
+ },
+ _ => unreachable!()
+ }
+ }
+
} \ No newline at end of file