Last active
December 8, 2019 00:43
-
-
Save KanoczTomas/3ac52ecf1e03b336ee488720bcdfa9a7 to your computer and use it in GitHub Desktop.
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
use std::ops::Add; | |
use std::ops::Mul; | |
use core::mem; | |
// very cool ideas!! | |
// https://functional.works-hub.com/learn/functional-programming-jargon-in-rust-1b555 | |
#[derive(Debug)] | |
struct Just<T>(T); | |
// below inspired by | |
// https://docs.rs/crate/functional/0.0.5/source/src/lib.rs | |
pub trait Generic1 { | |
type Type; | |
} | |
pub trait Rebind1<K> : Generic1 { | |
type Type; | |
} | |
pub trait Pointed<T>{ | |
fn of(t: T)-> Self; | |
} | |
pub trait Functor<T> : Generic1 { | |
/// Apply function to value(s) in the functor producing new functor with same type | |
fn map<K, F: Fn(<Self as Generic1>::Type)->K>(self, f: F) -> <Self as Rebind1<K>>::Type where Self: Rebind1<K>; | |
} | |
//============ impl Functor for Just<T> begin ============= | |
impl<T> Generic1 for Just<T>{ | |
type Type = T; | |
} | |
impl<T,K> Rebind1<K> for Just<T> where Just<T>: Generic1<Type=T> { | |
type Type = Just<K>; | |
} | |
impl<T> Pointed<T> for Just<T> { | |
fn of(t: T) -> Just<T>{ | |
Just(t) | |
} | |
} | |
impl<T> Functor<T> for Just<T> { | |
fn map<K, F: Fn(<Just<T> as Generic1>::Type)->K>(self, f: F) -> <Just<T> as Rebind1<K>>::Type{ | |
let Just(val) = self; | |
Just::of(f(val)) | |
} | |
} | |
//============ impl Functor for Just<T> end ============= | |
//============ impl Functor for Vec<T> begin ============= | |
impl<T> Generic1 for Vec<T>{ | |
type Type = T; | |
} | |
impl<T,K> Rebind1<K> for Vec<T> where Vec<T>: Generic1<Type=T> { | |
type Type = Vec<K>; | |
} | |
impl<T> Pointed<T> for Vec<T> { | |
fn of(t: T) -> Vec<T>{ | |
vec![t] | |
} | |
} | |
impl<T: Copy> Functor<T> for Vec<T> { | |
fn map<K, F: Fn(<Vec<T> as Generic1>::Type)->K>(self, f: F) -> <Vec<T> as Rebind1<K>>::Type { | |
// let mut vec = Vec::new(); | |
// for elem in self.iter(){ | |
// vec.push(f(*elem)); | |
// } | |
// vec | |
self.iter().map(|x| f(*x)).collect() | |
} | |
} | |
//============ impl Functor for Vec<T> end ============= | |
pub trait Foldable: IntoIterator { | |
fn fold<T, F> (&mut self, init: T, mut reducer: F) -> T where | |
Self: Sized + Clone, F: FnMut(T, Self::Item) -> T | |
{ | |
let mut acc = init; | |
for elem in self.clone().into_iter() { | |
acc = reducer(acc, elem); | |
} | |
acc | |
} | |
} | |
impl<T> Foldable for Vec<T> {} | |
// I did not find how to do 2 * T, do not know how to tell the compiler to convert 2 as test | |
// so a simple trick was used. Double means add yourself to yourself two times :) | |
fn double<T: Add + Copy>(a: T) -> T::Output { | |
a + a | |
} | |
//lets try to define a curried version of multiply | |
fn multiply<A: Mul + Copy> (a: A) -> impl Fn(A) -> A::Output{ | |
move |b| a * b | |
} | |
fn sum<T: Add>(a:T, b: T) -> T::Output { | |
a + b | |
} | |
// reduce => F as Foldable :: (a -> b -> a) -> a -> F b -> a | |
fn reduce<A, F> (reducer: impl Fn(A, F::Item) -> A, init: A, foldable: F) -> A where | |
F: IntoIterator, | |
{ | |
let mut acc = init; | |
for elem in foldable.into_iter() { | |
acc = reducer(acc, elem); | |
} | |
acc | |
} | |
// fn reduce_curried<A: 'static, F: 'static> (reducer: Box<dyn Fn(A, F::Item) -> A>) -> Box<dyn FnOnce(A) -> Box<dyn FnOnce(F) -> A >> where | |
fn reduce_curried<A: 'static, F: 'static> (reducer: fn(A, F::Item) -> A) -> Box<dyn FnOnce(A) -> Box<dyn FnOnce(F) -> A >> where | |
F: IntoIterator, | |
{ | |
Box::new(move |init: A|{ //Fn(A) -> Box<dyn Box<dyn Fn(F) -> A >> | |
Box::new(move |foldable: F| {//Box<dyn Fn(F) -> A > | |
let mut acc = init; | |
for elem in foldable.into_iter() { | |
acc = reducer(acc, elem); | |
} | |
acc | |
}) | |
}) | |
} | |
// map => Functor F :: (a -> b) -> F a -> F b | |
fn map <A : Copy,B, F> (mapper: impl Fn(A) -> B, foldable: &[A]) -> B where | |
B: std::iter::FromIterator<B> | |
{ | |
foldable.iter().map( | |
|a| mapper(*a) | |
).collect() | |
} | |
#[derive(Debug)] | |
struct Person { | |
name: String | |
} | |
impl Person { | |
fn new<S> (name: S) -> Person where S: Into<String> { | |
Person{ name: name.into()} | |
} | |
} | |
//https://stackoverflow.com/questions/45786955/how-to-compose-functions-in-rust | |
// compose_two :: (b -> c) -> (a -> b) -> c | |
fn compose_two<A, B, C, F, G> (f: F, g: G) -> impl Fn(A) -> C where | |
G: Fn(A) -> B, | |
F: Fn(B) -> C | |
{ | |
move |x| f(g(x)) | |
} | |
macro_rules! compose { | |
( $last:expr ) => { $last }; | |
( $head:expr, $( $tail:expr ),+ ) => { | |
compose_two($head, compose!($($tail),+)) | |
}; | |
} | |
fn add<T : Add + Copy> (a:T) -> impl Fn(T) -> T::Output { | |
move |b| a + b | |
} | |
fn main(){ | |
println!("{:?}", Just::of(3)); | |
println!("{:?}", Just::of("ahoj")); | |
println!("{:?}", Just::of(13.2)); | |
println!("{:?}", Just::of(vec![1,2,3])); | |
println!("{:?}", Just::of([1,2,3])); | |
println!("{:?}", Just::of(5).map(double)); | |
println!("{:?}", Vec::of(5)); | |
println!("{:?}", Vec::of([1,2,3])); | |
println!("{:?}", vec![1,2,3,4,5].map(double)); | |
println!("{:?}", vec![1,2,3,4,5].map(multiply(3))); | |
println!("{:?}", vec![1.3,2.2,3.5,4.5,5.3].map(multiply(3 as f32))); | |
println!("{:?}", vec![1.3,2.2,3.5,4.5,5.3].fold(0.into(), sum)); | |
println!("{:?}", vec![1,2,3,4,5].fold(0, sum)); | |
println!("{:?}", reduce(sum, 0, vec![1,2,3,4])); | |
// println!("{:?}", reduce_curried(Box::new(sum)) (0) (vec![1,2,3,4])); //not using a Box, but a fn pointer now | |
println!("{:?}", reduce_curried(sum) (0) (vec![1,2,3,4])); | |
// let vec = vec![1,2,3,4]; | |
// println!("{:?}", map(double, &vec[..])); | |
println!("{:?}", Person::new("Tomas")); | |
println!("{:?}", Person::new(String::from("Tomas"))); | |
println!("{:?}", mem::size_of::<i32>()); | |
let function = compose!(multiply(10), double, add(3)); | |
println!("funtion(10) = {}", function(10)); | |
} | |
// $ cargo run | |
// Just(3) | |
// Just("ahoj") | |
// Just(13.2) | |
// Just([1, 2, 3]) | |
// Just([1, 2, 3]) | |
// Just(10) | |
// [5] | |
// [[1, 2, 3]] | |
// [2, 4, 6, 8, 10] | |
// [3, 6, 9, 12, 15] | |
// [3.8999999, 6.6000004, 10.5, 13.5, 15.900001] | |
// 16.8 | |
// 15 | |
// 10 | |
// 10 | |
// Person { name: "Tomas" } | |
// Person { name: "Tomas" } | |
// 4 | |
// funtion(10) = 260 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment