From 1bdd780f02b5ba57795820360d19b241cb0dd006 Mon Sep 17 00:00:00 2001 From: Andreas Grois Date: Thu, 23 Mar 2023 00:00:08 +0100 Subject: Minor docs update and addition of one unit test. --- Cargo.toml | 9 +++++---- src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++-- 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 -- cgit v1.2.3