Last active
November 27, 2024 15:58
-
-
Save Sgeo/ecee21895815fb2066e3 to your computer and use it in GitHub Desktop.
Anonymous sum type prototype
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::marker::PhantomData; | |
pub enum Void {} | |
impl Void { | |
fn any(&self) -> ! { | |
match *self {} | |
} | |
} | |
trait UnwrapVoid<R> { | |
fn unwrap_void(self) -> R; | |
} | |
impl<R> UnwrapVoid<R> for Result<R, Void> { | |
fn unwrap_void(self) -> R { | |
match self { | |
Ok(r) => r, | |
Err(void) => void.any() | |
} | |
} | |
} | |
#[allow(dead_code)] | |
enum Here {} | |
#[allow(dead_code)] | |
struct There<T>(PhantomData<T>); | |
enum Cans<Head, Tail> { | |
Here(Head), | |
There(Tail) | |
} | |
trait NewCans<Item, Where> { | |
fn new(item: Item) -> Self; | |
} | |
impl<Item, Tail> NewCans<Item, Here> for Cans<Item, Tail> { | |
fn new(item: Item) -> Self { | |
Cans::Here(item) | |
} | |
} | |
impl<Item, Head, Tail, TailIndex> NewCans<Item, There<TailIndex>> for Cans<Head, Tail> | |
where Tail: NewCans<Item, TailIndex> { | |
fn new(item: Item) -> Self { | |
Cans::There(NewCans::new(item)) | |
} | |
} | |
impl<Head, Tail> Cans<Head, Tail> { | |
pub fn new<Item, Where>(item: Item) -> Self | |
where Self: NewCans<Item, Where> { | |
NewCans::new(item) | |
} | |
} | |
trait Find<T, Where> { | |
fn find(&self) -> Option<&T>; | |
fn find_mut(&mut self) -> Option<&mut T>; | |
} | |
impl<T, Tail> Find<T, Here> for Cans<T, Tail> { | |
fn find(&self) -> Option<&T> { | |
match *self { | |
Cans::Here(ref t) => Some(t), | |
Cans::There(_) => None, | |
} | |
} | |
fn find_mut(&mut self) -> Option<&mut T> { | |
match *self { | |
Cans::Here(ref mut t) => Some(t), | |
Cans::There(_) => None | |
} | |
} | |
} | |
impl<Head, T, Tail, TailIndex> Find<T, There<TailIndex>> for Cans<Head, Tail> | |
where Tail: Find<T, TailIndex> { | |
fn find(&self) -> Option<&T> { | |
match *self { | |
Cans::Here(_) => None, | |
Cans::There(ref there) => there.find() | |
} | |
} | |
fn find_mut(&mut self) -> Option<&mut T> { | |
match *self { | |
Cans::Here(_) => None, | |
Cans::There(ref mut there) => there.find_mut() | |
} | |
} | |
} | |
trait Select<T, R, Where> { | |
type Remainder; | |
fn select<F>(self, F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R; | |
} | |
impl<T, R, Tail> Select<T, R, Here> for Cans<T, Tail> { | |
type Remainder = Tail; | |
fn select<F>(self, f: F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R { | |
match self { | |
Cans::Here(t) => Ok(f(t)), | |
Cans::There(there) => Err(there) | |
} | |
} | |
} | |
impl<T, R, Head, Tail, TailIndex> Select<T, R, There<TailIndex>> for Cans<Head, Tail> | |
where Tail: Select<T, R, TailIndex> { | |
type Remainder = Cans<Head, Tail::Remainder>; | |
fn select<F>(self, f: F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R { | |
match self { | |
Cans::Here(t) => Err(Cans::Here(t)), | |
Cans::There(there) => there.select(f).map_err(|tail| Cans::There(tail)) | |
} | |
} | |
} | |
impl<T, R, Selectable, Index> Select<T, R, Index> for Result<R, Selectable> | |
where Selectable: Select<T, R, Index> { | |
type Remainder = Selectable::Remainder; | |
fn select<F>(self, f: F) -> Result<R, Self::Remainder> | |
where F: FnOnce(T) -> R{ | |
self.or_else(|sel| sel.select(f)) | |
} | |
} | |
trait Reshape<Dest, Indices> { | |
fn reshape(self) -> Dest; | |
} | |
impl<Dest> Reshape<Dest, ()> for Void { | |
fn reshape(self) -> Dest { | |
self.any() | |
} | |
} | |
impl<Dest, SHead, STail, HIndex, TIndices> Reshape<Dest, (HIndex, TIndices)> for Cans<SHead, STail> | |
where STail: Reshape<Dest, TIndices>, | |
Dest: NewCans<SHead, HIndex> { | |
fn reshape(self) -> Dest { | |
match self { | |
Cans::Here(shead) => NewCans::new(shead), | |
Cans::There(stail) => stail.reshape() | |
} | |
} | |
} | |
fn main() { | |
let cans: Cans<i32, Cans<String, Void>> = Cans::new("Hello".to_string()); | |
{ | |
let s: Option<&String> = cans.find(); | |
let t: Option<&i32> = cans.find(); | |
println!("{:?}", s); | |
println!("{:?}", t); | |
} | |
let foo = cans.select(|s: String| "It's a string!").select(|i: i32| "It's an i32!").unwrap_void(); | |
println!("{:?}", foo); | |
let cans2: Cans<i32, Cans<String, Void>> = Cans::new("Hello".to_string()); | |
let cans3: Cans<String, Cans<i32, Cans<i64, Void>>> = cans2.reshape(); | |
} |
#![feature(decl_macro)]
use std::marker::PhantomData;
#[derive(Clone, Debug)]
pub enum Void {}
impl Void {
fn any(&self) -> ! {
match *self {}
}
}
#[allow(dead_code)]
pub trait Unwrap<R> {
fn unwrap(self) -> R;
}
impl<R> Unwrap<R> for Result<R, Void> {
fn unwrap(self) -> R {
match self {
Ok(r) => r,
Err(void) => void.any(),
}
}
}
pub enum HeadMarker {}
pub struct TailMarker<T>(PhantomData<T>);
#[derive(Clone, Debug)]
pub enum Poly_<Head, Tail> {
Head(Head),
Tail(Tail),
}
pub trait Poly<Item, Where> {
fn new(item: Item) -> Self;
}
impl<Item, Tail> Poly<Item, HeadMarker> for Poly_<Item, Tail> {
fn new(item: Item) -> Self {
Poly_::Head(item)
}
}
impl<Item, Head, Tail, TailIndex> Poly<Item, TailMarker<TailIndex>> for Poly_<Head, Tail>
where
Tail: Poly<Item, TailIndex>,
{
fn new(item: Item) -> Self {
Poly_::Tail(Poly::new(item))
}
}
#[allow(dead_code)]
impl<A, B> Poly_<A, B> {
pub fn new<Item, Where>(item: Item) -> Self
where
Self: Poly<Item, Where>,
{
Poly::new(item)
}
}
pub trait Find<T, Where> {
/// Given that `P` is isomorphic to `poly![A, B]`, one of the following method calls
/// will successfully return `Some(&T)`: `P.find() as A`, `P.find() as B`
///
/// Example:
/// ```rs
/// use poly::{poly, Poly, Find, Void};
///
/// fn test() {
/// let p: poly![u32, i32] = Poly::new(123u32);
/// let a: Option<&u32> = p.find();
/// if let Some(a) = a {
/// println!("{a}");
/// }
/// }
/// ```
fn find(&self) -> Option<&T>;
fn find_mut(&mut self) -> Option<&mut T>;
}
impl<T, Tail> Find<T, HeadMarker> for Poly_<T, Tail> {
fn find(&self) -> Option<&T> {
match *self {
Poly_::Head(ref t) => Some(t),
Poly_::Tail(_) => None,
}
}
fn find_mut(&mut self) -> Option<&mut T> {
match *self {
Poly_::Head(ref mut t) => Some(t),
Poly_::Tail(_) => None,
}
}
}
impl<Head, T, Tail, TailIndex> Find<T, TailMarker<TailIndex>> for Poly_<Head, Tail>
where
Tail: Find<T, TailIndex>,
{
fn find(&self) -> Option<&T> {
match *self {
Poly_::Head(_) => None,
Poly_::Tail(ref there) => there.find(),
}
}
fn find_mut(&mut self) -> Option<&mut T> {
match *self {
Poly_::Head(_) => None,
Poly_::Tail(ref mut there) => there.find_mut(),
}
}
}
pub trait Select<T, R, Where> {
type Remainder;
fn select<F>(self, _: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R;
}
impl<T, R, Tail> Select<T, R, HeadMarker> for Poly_<T, Tail> {
type Remainder = Tail;
fn select<F>(self, f: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R,
{
match self {
Poly_::Head(t) => Ok(f(t)),
Poly_::Tail(there) => Err(there),
}
}
}
impl<T, R, Head, Tail, TailIndex> Select<T, R, TailMarker<TailIndex>> for Poly_<Head, Tail>
where
Tail: Select<T, R, TailIndex>,
{
type Remainder = Poly_<Head, Tail::Remainder>;
fn select<F>(self, f: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R,
{
match self {
Poly_::Head(t) => Err(Poly_::Head(t)),
Poly_::Tail(there) => there.select(f).map_err(|tail| Poly_::Tail(tail)),
}
}
}
impl<T, R, Selectable, Index> Select<T, R, Index> for Result<R, Selectable>
where
Selectable: Select<T, R, Index>,
{
type Remainder = Selectable::Remainder;
fn select<F>(self, f: F) -> Result<R, Self::Remainder>
where
F: FnOnce(T) -> R,
{
self.or_else(|sel| sel.select(f))
}
}
pub trait Mash<Dest, Indices> {
fn mash(self) -> Dest;
}
impl<Dest> Mash<Dest, ()> for Void {
fn mash(self) -> Dest {
self.any()
}
}
impl<Dest, SHead, STail, HIndex, TIndices> Mash<Dest, (HIndex, TIndices)> for Poly_<SHead, STail>
where
STail: Mash<Dest, TIndices>,
Dest: Poly<SHead, HIndex>,
{
fn mash(self) -> Dest {
match self {
Poly_::Head(shead) => Poly::new(shead),
Poly_::Tail(stail) => stail.mash(),
}
}
}
pub macro poly {
() => {
$crate::poly::Void
},
($head:ty $(, $tail:ty)*) => {
$crate::poly::Poly_<$head, poly!($($tail),*) >
}
}
For example
Reshape
could be left as is instead of Mash
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sorry for 2 weeks of silence
This is the cleanest implementation I've seen so far, and also the smallest one. It could be refactored to be a little more better named, like
Polymorph
orPoly
instead ofCans