Skip to content

Instantly share code, notes, and snippets.

@burjui
Last active May 28, 2021 01:27
Show Gist options
  • Save burjui/4ec90b395975709b79f999839dcf9674 to your computer and use it in GitHub Desktop.
Save burjui/4ec90b395975709b79f999839dcf9674 to your computer and use it in GitHub Desktop.
Vec and Option monads
/// 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();
}
@GrayJack
Copy link

Why can't we define app as

impl<A:Clone> 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 + Clone,
            <Self as Plug<F>>::Result: Clone,
    {
         match fs {
             Some(f) => self.fmap(f),
             None => None,
          }
    }
}

@burjui
Copy link
Author

burjui commented Aug 15, 2019

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 😄

@GrayJack
Copy link

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