6 个版本

使用旧的 Rust 2015

0.0.7 2016 年 10 月 20 日
0.0.6 2016 年 10 月 20 日

#1147 in Rust 模式

34 每月下载量

MIT 许可证

47KB
1K SLoC

Frust Crates.io 构建状态

在 Rust 中的实用函数式编程工具集。仍然主要是一个 WIP。

总体思路是通过在 Rust 中提供 FP 工具来简化事物,以便进行类似这样的操作

use frust::monoid::*;

let v = vec![Some(1), Some(3)];
assert_eq!(combine_all(&v), Some(4));

// Slightly more magical
let t1 =       (1, 2.5f32,                String::from("hi"),  Some(3));
let t2 =       (1, 2.5f32,            String::from(" world"),     None);
let t3 =       (1, 2.5f32,         String::from(", goodbye"), Some(10));
let tuples = vec![t1, t2, t3];

let expected = (3, 7.5f32, String::from("hi world, goodbye"), Some(13));
assert_eq!(combine_all(&tuples), expected);

目录

  1. 幺半群
  2. 半群
  3. HList
  4. 验证
  5. 待办事项
  6. 贡献
  7. 灵感

示例

幺半群

可以组合的事物。

use frust::semigroup::*;

assert_eq!(Some(1).combine(&Some(2)), Some(3));

assert_eq!(All(3).combine(&All(5)), All(1)); // bit-wise && 
assert_eq!(All(true).combine(&All(false)), All(false));

半群

可以组合 并且 具有空/标识值的事物。

use frust::monoid::*;

let t1 = (1, 2.5f32, String::from("hi"), Some(3));
let t2 = (1, 2.5f32, String::from(" world"), None);
let t3 = (1, 2.5f32, String::from(", goodbye"), Some(10));
let tuples = vec![t1, t2, t3];

let expected = (3, 7.5f32, String::from("hi world, goodbye"), Some(13));
assert_eq!(combine_all(&tuples), expected)

let product_nums = vec![Product(2), Product(3), Product(4)];
assert_eq!(combine_all(&product_nums), Product(24))

HList

静态类型异构列表。从这些列表中弹出多少都可以;所有内容都保持类型化。

#[macro_use] extern crate frust;
use frust::hlist::*;

let h = hlist![true, "hello", Some(41)];
let (h1, tail1) = h.pop();
assert_eq!(h1, true);
assert_eq!(tail1, hlist!["hello", Some(41)]);

验证

Validated 是执行一系列可能会出错的操作(例如,返回 Result<T, E> 的函数)的方式,在出现一个或多个错误的情况下,将所有错误一次性返回给你。如果一切顺利,你将获得一个包含所有结果的 HList

映射(以及使用纯 Result)是不同的,因为它会在遇到第一个错误时停止,这在非常常见的情况下可能会很烦人(如 Cats 项目 所概述的)。

以下是如何使用它的示例。

#[derive(PartialEq, Eq, Debug)]
struct Person {
    age: i32,
    name: String,
}

fn get_name() -> Result<String, Error> { /* elided */ }

fn get_age() -> Result<i32, Error> { /* elided */ }

// Build up a `Validated`
let validation = get_name().into_validated() + get_age();
// When needed, turn the `Validated` back into a Result and map as usual
let try_person = validation.into_result()
                           .map(|hlist| {
                               let (name, (age, _)) = hlist.into_tuple2();
                               Person {
                                   name: name,
                                   age: age,
                               }
                           });

assert_eq!(person,
           Result::Ok(Person {
               name: "James".to_owned(),
               age: 32,
           }));

/// This next pair of functions always return Recover::Err 
fn get_name_faulty() -> Result<String, String> {
    Result::Err("crap name".to_owned())
}

fn get_age_faulty() -> Result<i32, String> {
    Result::Err("crap age".to_owned())
}

let validation2 = get_name_faulty().into_validated() + get_age_faulty();
let try_person2 = validation2.into_result()
                             .map(|_| unimplemented!());

// Notice that we have an accumulated list of errors!
assert_eq!(try_person2,
           Result::Err(vec!["crap name".to_owned(), "crap age".to_owned()]));
    

待办事项

最好从实现那些对惯用 Rust 语法使用有用的东西开始(高效且安全)。以下可能很有用

  1. 验证(见 cats)

这些功能根本未实现,而且由于Rust不支持高阶类型,我也没有确切知道它们是否可能实现。此外,Rustaceans习惯于在集合上调用iter()来获取懒视图,操作它们的列表,然后在最后进行collect()来保持效率。在这些结构中的应用可能受到限制。

  1. 函子
  2. 单子
  3. 应用
  4. 应用函子

ShowMonoidHListSemigroup至少部分(大多数?)已实现。

基准测试会很棒,但它们是一个不稳定的特性,所以也许在不同的分支中。

贡献

是的,请!

以下内容被认为是重要的,符合Rust和函数式编程的精神。

  • 安全性(类型和内存)
  • 效率
  • 正确性

灵感

Scalaz、Cats、Haskell,常见的候选者 ;)

无运行时依赖