Skip to content

Instantly share code, notes, and snippets.

@KanoczTomas
Last active December 8, 2019 00:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KanoczTomas/3ac52ecf1e03b336ee488720bcdfa9a7 to your computer and use it in GitHub Desktop.
Save KanoczTomas/3ac52ecf1e03b336ee488720bcdfa9a7 to your computer and use it in GitHub Desktop.
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