https://github.com/centril/refl
Provides a Refl encoding in Rust
https://github.com/centril/refl
gadt propositional-logic rust type-system
Last synced: 5 months ago
JSON representation
Provides a Refl encoding in Rust
- Host: GitHub
- URL: https://github.com/centril/refl
- Owner: Centril
- License: apache-2.0
- Created: 2018-01-28T14:14:01.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2023-04-06T04:53:38.000Z (about 2 years ago)
- Last Synced: 2024-04-24T11:56:49.379Z (about 1 year ago)
- Topics: gadt, propositional-logic, rust, type-system
- Language: Rust
- Size: 20.5 KB
- Stars: 68
- Watchers: 3
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE-APACHE
Awesome Lists containing this project
README
# `refl`
[](https://travis-ci.org/Centril/refl)
[](https://crates.io/crates/refl)Provides a `refl` encoding which you can use to provide a proof
witness that one type is equivalent (identical) to another type.
You can use this to encode a subset of what GADTs allow you to in Haskell.This is encoded as:
```rust
use std::mem;
use std::marker::PhantomData;pub struct Id(PhantomData<(*mut S, *mut T)>);
impl Id { pub const REFL: Self = Id(PhantomData); }
pub fn refl() -> Id { Id::REFL }
impl Id {
/// Casts a value of type `S` to `T`.
///
/// This is safe because the `Id` type is always guaranteed to
/// only be inhabited by `Id` 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
}
}// ..
}
```In Haskell, the `Id` type corresponds to:
```haskell
data a :~: b where
Refl :: a :~: a
```However, note that you must do the casting manually with `refl.cast(val)`.
Rust will not know that `S == T` by just pattern matching on `Id`
(which you can't do).# Limitations
Please note that Rust has no concept of higher kinded types (HKTs) and so
we can not provide the general transformation `F -> F` given that
`S == T`. With the introduction of generic associated types (GATs), it
may be possible to introduce more transformations.# Example - A GADT-encoded expression type
```rust
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 {
Lit(T::Repr),
Add(Id, Box>, Box>),
If(Box>, Box>, Box>),
}fn eval(expr: &Expr) -> 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 =
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);
}
```## Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.