Skip to content

Commit

Permalink
docs: cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasdewally committed Sep 26, 2024
1 parent 8f5c749 commit 2fdc10b
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 74 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use uniplate::{Uniplate,Biplate};
use uniplate::derive::Uniplate;
#[derive(Clone,PartialEq,Eq,Debug,Uniplate)]
#[uniplate()]
#[biplate(to=String])]
#[biplate(to=String)]
enum Expr {
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Expand All @@ -89,7 +89,7 @@ enum Expr {
}

fn vars_names(expr: &Expr) -> Vec<String>{
<Expr as Biplate<String>>::universe_bi(expr).into_iter().collect();
<Expr as Biplate<String>>::universe_bi(expr).into_iter().collect()
}
```

Expand Down Expand Up @@ -151,7 +151,7 @@ enum Expr {
}

fn vars_names(stmt: &Stmt) -> Vec<String>{
<Stmt as Biplate<String>>::universe_bi(stmt).into_iter().collect();
<Stmt as Biplate<String>>::universe_bi(stmt).into_iter().collect()
}

```
Expand Down
2 changes: 1 addition & 1 deletion uniplate/examples/stmt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(dead_code)]

use uniplate::{Biplate, Uniplate};
use uniplate::derive::Uniplate;
use uniplate::{Biplate, Uniplate};

#[derive(Eq, PartialEq, Clone, Debug, Uniplate)]
#[uniplate()]
Expand Down
4 changes: 2 additions & 2 deletions uniplate/src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Implementations of Uniplate and Biplate for common types
//! Implementations of Uniplate and Biplate for common types.
//!
//! This includes stdlib types as well as common collections
//!
Expand All @@ -11,10 +11,10 @@
use im::Vector;
use std::collections::VecDeque;

use crate::{Uniplate,Biplate};
use crate::derive_iter;
use crate::derive_unplateable;
use crate::Tree::*;
use crate::{Biplate, Uniplate};

derive_unplateable!(i8);
derive_unplateable!(i16);
Expand Down
93 changes: 37 additions & 56 deletions uniplate/src/intro.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
**Uniplate helps you write simple, boilerplate-free operations on tree shaped data types.**

A port of Haskell's [Uniplate](https://hackage.haskell.org/package/uniplate) in
Rust.

---
- A port of Haskell's [Uniplate](https://hackage.haskell.org/package/uniplate)
library in Rust.

# Getting Started

*Adapted from (Mitchell and Runciman 2009)*
*Adapted from (Mitchell and Runciman 2007)*

Consider the abstract syntax tree for a simple calculator language:

Expand All @@ -28,19 +26,19 @@ Say we want to list all the used variable names inside a given expression:
```rust
# use uniplate::test_common::paper::Expr::*;
# use uniplate::test_common::paper::Expr;
fn vars(expr: &Expr) -> Vec<String>{
fn var_names(expr: &Expr) -> Vec<String>{
match expr {
Add(a,b) => {
[vars(a),vars(b)].concat()
[var_names(a),var_names(b)].concat()
},
Sub(a,b) => {
[vars(a),vars(b)].concat()
[var_names(a),var_names(b)].concat()
},
Mul(a,b) => {
[vars(a),vars(b)].concat()
[var_names(a),var_names(b)].concat()
},
Div(a,b) => {
[vars(a),vars(b)].concat()
[var_names(a),var_names(b)].concat()
},
Val(a) => {
Vec::new()
Expand All @@ -49,7 +47,7 @@ fn vars(expr: &Expr) -> Vec<String>{
vec![a.clone()]
},
Neg(a) =>{
vars(a)
var_names(a)
}
}
}
Expand All @@ -66,7 +64,7 @@ With Uniplate, this boilerplate can be eliminated:
# use uniplate::test_common::paper::Expr::*;
# use uniplate::test_common::paper::Expr;
use uniplate::Biplate;
fn vars(expr: &Expr) -> Vec<String>{
fn var_names(expr: &Expr) -> Vec<String>{
<Expr as Biplate<String>>::universe_bi(expr).into_iter().collect()
}
```
Expand All @@ -75,8 +73,8 @@ The functionality of Uniplate comes from two main traits: [`Uniplate`](Uniplate)
[`Biplate<T>`](Biplate).

* The [`Uniplate`](Uniplate) of `Expr` operates over all nested `Expr`s.
* The [`Biplate<T>`](Biplate) of `Expr` operates over all nested values of some given type `T` within the
expression tree.
* The [`Biplate<T>`](Biplate) of `Expr` operates over all nested values of type
`T` in the expression tree.

These traits provide traversal operations (e.g. [`children`](Uniplate::children)) as well as
functional programming constructs such as [`map`](Uniplate::map) and [`fold`](Uniplate::fold).
Expand All @@ -86,11 +84,12 @@ The easiest way to use Uniplate is with the derive macro.

## Derive Macro

When no arguments are provided, the macro derives a Uniplate instance:
To derive Uniplate instances, use the `#[uniplate]` attribute:

```rust
use uniplate::derive::Uniplate;
#[derive(Clone,PartialEq,Eq,Debug,Uniplate)]
#[uniplate()]
enum Expr {
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Expand Down Expand Up @@ -122,7 +121,8 @@ enum Expr {

## Multi-type traversals

Lets expand our calculator language to include statements as well as expressions:
Uniplate also supports trees with multiple recursive types. Lets extend our
calculator language to include statements as well as expressions:

```rust
enum Expr {
Expand All @@ -143,41 +143,28 @@ enum Stmt {
}
```

When looking for `Strings` in a given `Stmt`, we may want to identify not only the strings
directly contained within a `Stmt`, but also any strings contained inside an `Expr` inside a
`Stmt`.

For example:
When looking for variable names in a given statement, we want to identify not
only the variable names directly used inside the statement, but also any
variable names used by child expressions:

```rust
# use uniplate::test_common::paper::Expr::*;
# use uniplate::test_common::paper::Expr::*;
# use uniplate::test_common::paper::Stmt;
# use uniplate::test_common::paper::Stmt::*;
use uniplate::{Biplate,Uniplate};
use uniplate::derive::Uniplate;
use uniplate::{Uniplate,Biplate};
#[derive(Clone,PartialEq,Eq,Debug,Uniplate)]
// look for strings inside expressions as well as statements
#[biplate(to=String,walk_into=[Expr])]
#[biplate(to=Expr)]
#[uniplate()]
enum Stmt {
Assign(String, Expr),
Sequence(Vec<Stmt>),
If(Expr, Box<Stmt>, Box<Stmt>),
While(Expr, Box<Stmt>),
}

let stmt = Assign("x".into(), Add(Box::new(Var("y".into())),Box::new(Val(10))));
let strings = <Stmt as Biplate<String>>::universe_bi(&stmt);

assert!(strings.contains(&"x".into()));

// Despite being inside an Expr::String, "y" is found by Biplate
assert!(strings.contains(&"y".into()));

assert_eq!(strings.len(), 2);
```


To do this, a list of types to "walk into" can be given as an argument to the Biplate
declaration:
```rust
use uniplate::Uniplate;
use uniplate::derive::Uniplate;
#[derive(Clone,PartialEq,Eq,Debug,Uniplate)]
#[biplate(to=String)]
#[uniplate()]
#[biplate(to=String,walk_into=[Expr])]
#[biplate(to=Stmt)]
enum Expr {
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Expand All @@ -188,20 +175,14 @@ enum Expr {
Neg(Box<Expr>),
}

// Uniplate also supports walk_into.
// In this case, it doesn't do much.
#[derive(Clone,PartialEq,Eq,Debug,Uniplate)]
#[biplate(to=String, walk_into=[Expr])]
#[biplate(to=Expr,walk_into=[Expr])]
#[uniplate(walk_into=[Expr])]
enum Stmt {
Assign(String, Expr),
Sequence(Vec<Stmt>),
If(Expr, Box<Stmt>, Box<Stmt>),
While(Expr, Box<Stmt>),
fn vars_names(stmt: &Stmt) -> Vec<String>{
<Stmt as Biplate<String>>::universe_bi(stmt).into_iter().collect()
}
```

The types given to the `walk_into` argument are recursed through by uniplate.
Both `#[uniplate]` and `#[biplate]` support the `walk_into` parameter.


# Bibliography

Expand Down
38 changes: 28 additions & 10 deletions uniplate/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#![doc = include_str!("intro.md")]
//! Uniplate provides simple and low-boilerplate ways to traverse and manipulate data structures.
//! A port of Haskell's [Uniplate](https://hackage.haskell.org/package/uniplate) in Rust.

#[doc(hidden)]
extern crate self as uniplate;
Expand All @@ -9,37 +7,47 @@ pub mod impls;
mod traits;
mod tree;

pub use traits::{Uniplate, Biplate};
pub use traits::{Biplate, Uniplate};

#[doc(hidden)]
pub use tree::Tree;

#[doc(hidden)]
pub mod test_common;

/// The derive macro.
pub mod derive {
pub use uniplate_derive::Uniplate as Uniplate;
pub use uniplate_derive::Uniplate;
}

#[doc(hidden)]
pub mod _dependencies {
pub use im;
}


/// Generates a Biplate and Uniplate instance for an unplateable type.
#[macro_export]
macro_rules! derive_unplateable {
($t:ty) => {
impl Uniplate for $t {
fn uniplate(&self) -> (::uniplate::Tree<Self>, Box<dyn Fn(::uniplate::Tree<Self>) -> Self>) {
fn uniplate(
&self,
) -> (
::uniplate::Tree<Self>,
Box<dyn Fn(::uniplate::Tree<Self>) -> Self>,
) {
let val = self.clone();
(::uniplate::Tree::Zero, Box::new(move |_| val.clone()))
}
}

impl Biplate<$t> for $t {
fn biplate(&self) -> (::uniplate::Tree<$t>, Box<dyn Fn(::uniplate::Tree<$t>) -> $t>) {
fn biplate(
&self,
) -> (
::uniplate::Tree<$t>,
Box<dyn Fn(::uniplate::Tree<$t>) -> $t>,
) {
let val = self.clone();
(
::uniplate::Tree::One(val.clone()),
Expand All @@ -50,7 +58,7 @@ macro_rules! derive_unplateable {
};
}

// Generates a Biplate and Uniplate instance for an iterable type.
/// Generates a Biplate and Uniplate instance for an iterable type.
#[macro_export]
macro_rules! derive_iter {
($iter_ty:ident) => {
Expand All @@ -59,7 +67,12 @@ macro_rules! derive_iter {
T: Clone + Eq + Uniplate + Sized + 'static,
F: Clone + Eq + Uniplate + Biplate<T> + Sized + 'static,
{
fn biplate(&self) -> (::uniplate::Tree<T>, Box<(dyn Fn(::uniplate::Tree<T>) -> $iter_ty<F>)>) {
fn biplate(
&self,
) -> (
::uniplate::Tree<T>,
Box<(dyn Fn(::uniplate::Tree<T>) -> $iter_ty<F>)>,
) {
if (self.is_empty()) {
let val = self.clone();
return (::uniplate::Tree::Zero, Box::new(move |_| val.clone()));
Expand Down Expand Up @@ -130,7 +143,12 @@ macro_rules! derive_iter {
where
T: Clone + Eq + Uniplate + Sized + 'static,
{
fn uniplate(&self) -> (::uniplate::Tree<Self>, Box<dyn Fn(::uniplate::Tree<Self>) -> Self>) {
fn uniplate(
&self,
) -> (
::uniplate::Tree<Self>,
Box<dyn Fn(::uniplate::Tree<Self>) -> Self>,
) {
let val = self.clone();
(Zero, Box::new(move |_| val.clone()))
}
Expand Down
2 changes: 1 addition & 1 deletion uniplate/src/test_common/paper.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::derive::Uniplate;
use crate::{Uniplate,Biplate};
use crate::{Biplate, Uniplate};
use prop::sample::SizeRange;
use proptest::prelude::*;

Expand Down
2 changes: 2 additions & 0 deletions uniplate/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::sync::Arc;
pub use super::Tree;
use im::vector;

/// `Biplate<U>` for type `T` operates over all values of type `U` within `T`.
pub trait Biplate<To>
where
Self: Sized + Clone + Eq + Uniplate + 'static,
Expand Down Expand Up @@ -54,6 +55,7 @@ where
}
}

/// `Uniplate` for type `T` operates over all values of type `T` within `T`.
pub trait Uniplate
where
Self: Sized + Clone + Eq + 'static,
Expand Down
2 changes: 1 addition & 1 deletion uniplate/tests/expr_stmt_manual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::iter::zip;

use im::vector;
//use uniplate::test_common::paper::*;
use uniplate::{Uniplate,Biplate,Tree};
use uniplate::{Biplate, Tree, Uniplate};

use self::Expr::*;

Expand Down

0 comments on commit 2fdc10b

Please sign in to comment.