Last active
May 28, 2021 01:27
-
-
Save burjui/4ec90b395975709b79f999839dcf9674 to your computer and use it in GitHub Desktop.
Vec and Option monads
This file contains 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
/// https://gist.github.com/edmundsmith/855fcf0cb35dd467c29a9350481f0ecf | |
struct Forall; | |
trait Unplug { | |
type F; | |
type A; | |
} | |
trait Plug<A> { | |
type Result; | |
} | |
trait Functor: Unplug+Plug<<Self as Unplug>::A> { | |
fn map<B, F>(self, f:F) -> <Self as Plug<B>>::Result | |
where | |
Self:Plug<B>, | |
F:FnMut(<Self as Unplug>::A) -> B | |
; | |
} | |
trait Applicative: Functor { | |
fn pure(s:<Self as Unplug>::A) -> Self; | |
fn app<B, F>( | |
self, f:<Self as Plug<F>>::Result, | |
) -> <Self as Plug<B>>::Result | |
where | |
F:FnMut(<Self as Unplug>::A) -> B + Clone, | |
Self:Plug<F> + Plug<B> + Unplug, | |
<Self as Plug<F>>::Result: | |
Unplug<F=<Self as Unplug>::F,A=F> + | |
Plug<F> + | |
Clone, | |
<Self as Unplug>::F:Plug<F> | |
; | |
} | |
trait Monad : Applicative { | |
fn bind<F,B>(self, f:F) -> <Self as Plug<B>>::Result | |
where | |
Self:Plug<F>+Plug<B>, | |
F:FnMut(<Self as Unplug>::A) -> | |
<Self as Plug<B>>::Result + Clone | |
; | |
} | |
// -------------- | |
impl<A,B> Plug<A> for Vec<B> { | |
type Result = Vec<A>; | |
} | |
impl<A> Unplug for Vec<A> { | |
type F=Vec<Forall>; | |
type A=A; | |
} | |
impl<A> Functor for Vec<A> { | |
fn map<B,F>(self, f:F) -> <Self as Plug<B>>::Result | |
where | |
F:FnMut(<Self as Unplug>::A) -> B | |
{ | |
self.into_iter().map(f).collect() | |
} | |
} | |
impl<A:Clone> Applicative for Vec<A> { | |
fn pure(a:A) -> Self { | |
vec![a] | |
} | |
fn app<B, F>( | |
self, fs:<Self as Plug<F>>::Result | |
) -> <Self as Plug<B>>::Result | |
where | |
F:FnMut(<Self as Unplug>::A) -> B + Clone, | |
<Self as Plug<F>>::Result: Clone, | |
{ | |
self.map(|x| | |
fs.clone().map(|f| f.clone()(x.clone()))) | |
.into_iter() | |
.map(|x|x) | |
.flatten() | |
.collect() | |
} | |
} | |
impl<A:Clone> Monad for Vec<A> { | |
fn bind<F,B>(self, mut f:F) -> | |
<Self as Plug<B>>::Result | |
where | |
F:FnMut(<Self as Unplug>::A) | |
-> <Self as Plug<B>>::Result | |
{ | |
self | |
.into_iter() | |
.map(|x| f(x)) | |
.flatten().collect() | |
} | |
} | |
fn vec_monad() { | |
fn x2(x: i32) -> i32 { x * 2 } | |
fn x20(x: i32) -> i32 { x * 20 } | |
let v = vec![1, 2, 3].app(vec![x2 as fn(i32) -> i32, x20]).bind(|x| vec![x + 100]); | |
println!("{:?}", v); | |
} | |
impl<A, B> Plug<B> for Option<A> { | |
type Result = Option<B>; | |
} | |
impl<A> Unplug for Option<A> { | |
type F = Option<Forall>; | |
type A = A; | |
} | |
impl<A> Functor for Option<A> { | |
fn map<B,F>(self, mut f:F) -> <Self as Plug<B>>::Result | |
where | |
F:FnMut(<Self as Unplug>::A) -> B | |
{ | |
match self { | |
Some(a) => Some(f(a)), | |
None => None, | |
} | |
} | |
} | |
impl<A> Applicative for Option<A> { | |
fn pure(a: Self::A) -> Self { | |
Some(a) | |
} | |
fn app<B, F>( | |
self, fs:<Self as Plug<F>>::Result | |
) -> <Self as Plug<B>>::Result | |
where | |
F:FnMut(<Self as Unplug>::A) -> B, | |
{ | |
match fs { | |
Some(f) => self.map(f), | |
None => None, | |
} | |
} | |
} | |
impl<A> Monad for Option<A> { | |
fn bind<F,B>(self, mut f:F) -> | |
<Self as Plug<B>>::Result | |
where | |
F:FnMut(<Self as Unplug>::A) | |
-> <Self as Plug<B>>::Result | |
{ | |
match self { | |
Some(a) => f(a), | |
None => None, | |
} | |
} | |
} | |
fn option_monad() { | |
let v = Some(1).bind(|x| Some(x * 2)).app(Some(|x| x + 1)); | |
println!("{:?}", v); | |
} | |
fn main() { | |
vec_monad(); | |
option_monad(); | |
} |
Because I, being a lazy ass, instead of thinking hard about it, just applied an ancient technique to the original Edmund's code, known as copy-paste-fix-compile loop. Thanks for the suggestion, now this pile of crap looks a bit nicer 😄
I'm doing this for my Category Class: https://github.com/GrayJack/gat
Where I'm implementing those thinks in Rust.
I had some headache implementing them, googling about it I found the Edmund's code.
If you want to, you can check it out my impl for Option, Result, Vec and LinkedList, but it lacks Monads
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Why can't we define app as