recursion/recursive/
collapse.rs

1use crate::frame::{expand_and_collapse, MappableFrame};
2
3/// The ability to recursively collapse some type into some output type, frame by frame.
4///
5/// # Example: A tree of integers
6///
7/// Here's an example showing how to use [`Collapsible`] to collapse a binary tree of integers,
8/// where nodes hold two subnodes and no data and leaves hold a single `usize` value
9///
10/// ```rust
11/// # use recursion::*;
12/// enum IntTree {
13///     Leaf { value: usize },
14///     Node { left: Box<Self>, right: Box<Self> },
15/// }
16///
17/// # impl IntTree {
18/// #     fn node(left: Self, right: Self) -> Self {
19/// #         Self::Node {
20/// #             left: Box::new(left),
21/// #             right: Box::new(right),
22/// #         }
23/// #     }
24/// #     fn leaf(value: usize) -> Self {
25/// #         Self::Leaf { value }
26/// #     }
27/// # }
28/// ```
29///
30/// ## Defining a frame type
31///
32/// For working with values of type `IntTree`, we'll define an `IntTreeFrame<A>` frame type
33/// that represents a single layer of the `IntTree` structure, with `A` subbed in for `Box<Self>`
34///
35/// ```rust
36/// # use recursion::*;
37/// enum IntTreeFrame<A> {
38///     Leaf { value: usize },
39///     Node { left: A, right: A },
40/// }
41/// impl MappableFrame for IntTreeFrame<PartiallyApplied> { /*...*/
42/// #    type Frame<X> = IntTreeFrame<X>;
43/// #
44/// #    fn map_frame<A, B>(input: Self::Frame<A>, mut f: impl FnMut(A) -> B) -> Self::Frame<B> {
45/// #         match input {
46/// #             IntTreeFrame::Leaf { value } => IntTreeFrame::Leaf { value },
47/// #             IntTreeFrame::Node { left, right } => IntTreeFrame::Node {
48/// #                 left: f(left),
49/// #                 right: f(right),
50/// #             },
51/// #         }
52/// #     }
53/// }
54/// ```
55///
56/// ## Implementing Collapsible
57///
58/// Then we can define a collapse instance for `IntTree`
59///
60/// ```rust
61/// # use recursion::*;
62/// # enum IntTree {
63/// #     Leaf { value: usize },
64/// #     Node { left: Box<Self>, right: Box<Self> },
65/// # }
66/// # impl IntTree {
67/// #   fn node(left: Self, right: Self) -> Self { Self::Node{left: Box::new(left), right: Box::new(right)}}
68/// #   fn leaf(value: usize) -> Self { Self::Leaf{value}}
69/// # }
70/// # enum IntTreeFrame<A> {
71/// #     Leaf { value: usize },
72/// #     Node { left: A, right: A },
73/// # }
74/// # impl MappableFrame for IntTreeFrame<PartiallyApplied> {
75/// #    type Frame<X> = IntTreeFrame<X>;
76/// #
77/// #    fn map_frame<A, B>(input: Self::Frame<A>, mut f: impl FnMut(A) -> B) -> Self::Frame<B> {
78/// #         match input {
79/// #             IntTreeFrame::Leaf { value } => IntTreeFrame::Leaf { value },
80/// #             IntTreeFrame::Node { left, right } => IntTreeFrame::Node {
81/// #                 left: f(left),
82/// #                 right: f(right),
83/// #             },
84/// #         }
85/// #     }
86/// # }
87/// impl<'a> Collapsible for &'a IntTree {
88///     type FrameToken = IntTreeFrame<PartiallyApplied>;
89///
90///     fn into_frame(self) -> <Self::FrameToken as MappableFrame>::Frame<Self> {
91///         match self {
92///             IntTree::Leaf { value } => IntTreeFrame::Leaf { value: *value },
93///             IntTree::Node { left, right } => IntTreeFrame::Node {
94///                 left: left.as_ref(),
95///                 right: right.as_ref(),
96///             },
97///         }
98///     }
99/// }
100/// ```
101///
102/// ## Collapsing a tree into a value
103///
104/// Finally, we can use our [`Collapsible`] instance to collapse an example tree into a single value.
105/// In this case, we're just doing something simple - counting the number of leaves in the structure
106///
107/// ```rust
108/// # use recursion::*;
109/// # #[derive(Debug, PartialEq, Eq)]
110/// # enum IntTree {
111/// #     Leaf { value: usize },
112/// #     Node { left: Box<Self>, right: Box<Self> },
113/// # }
114/// # impl IntTree {
115/// #   fn node(left: Self, right: Self) -> Self { Self::Node{left: Box::new(left), right: Box::new(right)}}
116/// #   fn leaf(value: usize) -> Self { Self::Leaf{value}}
117/// # }
118///
119/// # enum IntTreeFrame<A> {
120/// #     Leaf { value: usize },
121/// #     Node { left: A, right: A },
122/// # }
123/// # impl MappableFrame for IntTreeFrame<PartiallyApplied> {
124/// #    type Frame<X> = IntTreeFrame<X>;
125/// #
126/// #    fn map_frame<A, B>(input: Self::Frame<A>, mut f: impl FnMut(A) -> B) -> Self::Frame<B> {
127/// #         match input {
128/// #             IntTreeFrame::Leaf { value } => IntTreeFrame::Leaf { value },
129/// #             IntTreeFrame::Node { left, right } => IntTreeFrame::Node {
130/// #                 left: f(left),
131/// #                 right: f(right),
132/// #             },
133/// #         }
134/// #     }
135/// # }
136/// # impl<'a> Collapsible for &'a IntTree {
137/// #     type FrameToken = IntTreeFrame<PartiallyApplied>;
138/// #
139/// #     fn into_frame(self) -> <Self::FrameToken as MappableFrame>::Frame<Self> {
140/// #         match self {
141/// #             IntTree::Leaf { value } => IntTreeFrame::Leaf { value: *value },
142/// #             IntTree::Node { left, right } => IntTreeFrame::Node {
143/// #                 left: left.as_ref(),
144/// #                 right: right.as_ref(),
145/// #             },
146/// #         }
147/// #     }
148/// # }
149/// let tree = IntTree::node(
150///     IntTree::node(IntTree::leaf(0), IntTree::leaf(0)),
151///     IntTree::node(IntTree::leaf(0), IntTree::leaf(0)),
152/// );
153///
154/// let leaf_count = tree.collapse_frames(|frame| match frame {
155///     IntTreeFrame::Leaf { value } => 1,
156///     IntTreeFrame::Node { left, right } => left + right,
157/// });
158///
159/// assert_eq!(leaf_count, 4)
160/// ```
161
162pub trait Collapsible
163where
164    Self: Sized,
165{
166    type FrameToken: MappableFrame;
167
168    /// Given an instance of this type, generate a frame holding the data owned by it,
169    /// with any recursive instances of `Self` owned by this node as the frame elements
170    fn into_frame(self) -> <Self::FrameToken as MappableFrame>::Frame<Self>;
171}
172
173pub trait CollapsibleExt: Collapsible
174where
175    Self: Sized,
176{
177    /// Given an instance of this type, collapse it into a single value of type `Out` by
178    /// traversing the recursive structure of `self`, generating frames, and collapsing
179    /// those frames using some function from `Frame<Out> -> Out`
180    fn collapse_frames<Out>(
181        self,
182        collapse_frame: impl FnMut(<Self::FrameToken as MappableFrame>::Frame<Out>) -> Out,
183    ) -> Out;
184
185    /// Given an instance of this type, collapse it into a single value of type `Result<Out, E>` by
186    /// traversing the recursive structure of `self`, generating frames, and collapsing
187    /// those frames using some function from `Frame<Out> -> Result<Out, E>`
188    fn try_collapse_frames<Out, E>(
189        self,
190        collapse_frame: impl FnMut(<Self::FrameToken as MappableFrame>::Frame<Out>) -> Result<Out, E>,
191    ) -> Result<Out, E>;
192}
193
194impl<X> CollapsibleExt for X
195where
196    X: Collapsible,
197{
198    fn collapse_frames<Out>(
199        self,
200        collapse_frame: impl FnMut(<Self::FrameToken as MappableFrame>::Frame<Out>) -> Out,
201    ) -> Out {
202        expand_and_collapse::<Self::FrameToken, Self, Out>(self, Self::into_frame, collapse_frame)
203    }
204
205    // TODO: add example here in this file
206    fn try_collapse_frames<Out, E>(
207        self,
208        collapse_frame: impl FnMut(<Self::FrameToken as MappableFrame>::Frame<Out>) -> Result<Out, E>,
209    ) -> Result<Out, E> {
210        crate::frame::try_expand_and_collapse::<Self::FrameToken, Self, Out, E>(
211            self,
212            |seed| Ok(Self::into_frame(seed)),
213            collapse_frame,
214        )
215    }
216}