6个版本
0.2.1 | 2020年2月24日 |
---|---|
0.2.0 | 2019年3月23日 |
0.1.3 | 2019年3月23日 |
0.1.2 | 2018年2月4日 |
0.1.1 | 2018年1月28日 |
在Rust模式中排名572
每月下载量134次
在12个crate(2个直接)中使用
15KB
69 行
refl
提供了一种 refl
编码,您可以使用它来提供一种证明证据,表明一种类型与另一种类型等价(相同)。您可以使用它来编码 Haskell 中 GADTs 允许您编码的一个子集。
编码如下
use std::mem;
use std::marker::PhantomData;
pub struct Id<S: ?Sized, T: ?Sized>(PhantomData<(*mut S, *mut T)>);
impl<T: ?Sized> Id<T, T> { pub const REFL: Self = Id(PhantomData); }
pub fn refl<T: ?Sized>() -> Id<T, T> { Id::REFL }
impl<S: ?Sized, T: ?Sized> Id<S, T> {
/// Casts a value of type `S` to `T`.
///
/// This is safe because the `Id` type is always guaranteed to
/// only be inhabited by `Id<T, T>` types by construction.
pub fn cast(self, value: S) -> T where S: Sized, T: Sized {
unsafe {
// Transmute the value;
// This is safe since we know by construction that
// S == T (including lifetime invariance) always holds.
let cast_value = mem::transmute_copy(&value);
// Forget the value;
// otherwise the destructor of S would be run.
mem::forget(value);
cast_value
}
}
// ..
}
在 Haskell 中,类型 Id<A, B>
对应于
data a :~: b where
Refl :: a :~: a
但是请注意,您必须手动使用 refl.cast(val)
进行类型转换。Rust 仅通过在 Id<S, T>
(您不能这样做)上进行模式匹配,并不能知道 S == T
。
限制
请注意,Rust 没有高阶类型(HKTs)的概念,因此我们无法在 F<S> -> F<T>
给定 S == T
的情况下提供通用转换。随着泛型关联类型(GATs)的引入,可能可以引入更多转换。
示例 - GADT 编码的表达式类型
extern crate refl;
use refl::*;
trait Ty { type Repr: Copy + ::std::fmt::Debug; }
#[derive(Debug)]
struct Int;
impl Ty for Int { type Repr = usize; }
#[derive(Debug)]
struct Bool;
impl Ty for Bool { type Repr = bool; }
#[derive(Debug)]
enum Expr<T: Ty> {
Lit(T::Repr),
Add(Id<usize, T::Repr>, Box<Expr<Int>>, Box<Expr<Int>>),
If(Box<Expr<Bool>>, Box<Expr<T>>, Box<Expr<T>>),
}
fn eval<T: Ty>(expr: &Expr<T>) -> T::Repr {
match *expr {
Expr::Lit(ref val) =>
*val,
Expr::Add(ref refl, ref l, ref r) =>
refl.cast(eval(&*l) + eval(&*r)),
Expr::If(ref c, ref i, ref e) =>
if eval(&*c) { eval(&*i) } else { eval(&*e) },
}
}
fn main() {
let expr: Expr<Int> =
Expr::If(
Box::new(Expr::Lit(false)),
Box::new(Expr::Lit(1)),
Box::new(Expr::Add(
refl(),
Box::new(Expr::Lit(2)),
Box::new(Expr::Lit(3)),
))
);
assert_eq!(eval(&expr), 5);
}
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义,您提交的任何贡献,有意将其包含在作品中的,应按上述方式双重许可,而不附加任何额外的条款或条件。