Chapter 1 Draft

master
Andrew Johnson 6 years ago
parent 16a59fa4a0
commit 93ed2cd683

@ -0,0 +1,44 @@
[package]
name = "Chapter1"
version = "1.0.0"
[dependencies]
lazy_static = "1"
cached = "0.5"
metaderive = { path = "metaderive" }
[[bin]]
name = "intro_binding"
path = "intro_binding.rs"
[[bin]]
name = "intro_datatypes"
path = "intro_datatypes.rs"
[[bin]]
name = "intro_expressions"
path = "intro_expressions.rs"
[[bin]]
name = "intro_functions"
path = "intro_functions.rs"
[[bin]]
name = "intro_generics"
path = "intro_generics.rs"
[[bin]]
name = "intro_iterators"
path = "intro_iterators.rs"
[[bin]]
name = "intro_metaprogramming"
path = "intro_metaprogramming.rs"
[[bin]]
name = "intro_mixoopfp"
path = "intro_mixoopfp.rs"
[[bin]]
name = "intro_patterns"
path = "intro_patterns.rs"

@ -0,0 +1,5 @@
# Chapter 1 Hands On Functional Programming in RUST
To build all examples from each chapter section, call "cargo build" from the command line. Executables will be created in the target/debug folder.

@ -0,0 +1,71 @@
use std::thread;
use std::sync::{Mutex, Arc};
use std::sync::mpsc::channel;
fn scoped() {
vec![1, 2, 3];
}
fn scoped2() -> Vec<u32> {
vec![1, 2, 3]
}
fn scoped3() {
let v1 = vec![1, 2, 3];
let v2 = v1;
//it is now illegal to reference v1,
//because ownership has been transferred to v2
}
fn scoped4() {
vec![1, 2, 3].clone();
"".to_string().clone();
}
fn scoped5() {
fn foo(v1: &Vec<u32>){}
let v1 = vec![1, 2, 3];
foo(&v1);
//v1 is still valid, ownership has been returned
v1;
}
fn thread1() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join();
}
fn thread2()
{
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
fn thread3() {
let (sender, receiver) = channel();
let handle = thread::spawn(move || {
//do work
let v = vec![1, 2, 3];
sender.send(v).unwrap();
});
handle.join();
receiver.recv().unwrap();
}
fn main() {
}

@ -0,0 +1,66 @@
//It can be helpful to create shorthand names for complex types
type Name = String;
//Structs can be repetitive if you just want a way to store multiple values together
struct Data1
{
a: i32,
b: f64,
c: String
}
struct Data2
{
a: u32,
b: String,
c: f64
}
//Tuples help eliminate redundant struct definitions
//no prior type definitions are needed here and the aliases are redundant
type Tuple1 = (i32, f64, String);
type Tuple2 = (u32, String, f64);
//Standard operators can be implemented with traits
//anyone coming from an ML family language may appreciate
use std::ops::Mul;
//Standard library collections etc. are generic
use std::collections::HashMap;
type CustomHashMap = HashMap<i32,u32>;
//Tagged Unions can be used to create typesafe definitions of structures that can't be safely described in pure OOP
enum BTree<T>
{
Branch { val:T, left:Box<BTree<T>>, right:Box<BTree<T>> },
Leaf { val:T }
}
//Commonly, Tagged Unions are used for complex data structures with many possible union options
enum Term
{
TermVal { value: String },
TermVar { symbol: String },
TermApp { f: Box<Term>, x: Box<Term> },
TermAbs { arg: String, body: Box<Term> }
}
//Traits are a bit like Object Classes
trait Data1Trait
{
//Traits can define constructors
fn new(a: i32, b: f64, c: String) -> Self;
//Traits can have methods, which reference "self"
fn get_a(&self) -> i32;
fn get_b(&self) -> f64;
fn get_c(&self) -> String;
}
//Traits are also like Data Classes
trait BehaviourOfShow
{
fn show(&self) -> String;
}
fn main() {
}

@ -0,0 +1,51 @@
struct MyStruct {
a: u32,
b: f32,
c: String
}
enum Term {
TermVal { value: String },
TermVar { symbol: String },
TermApp { f: Box<Term>, x: Box<Term> },
TermAbs { arg: String, body: Box<Term> }
}
fn main() {
let x = {
fn f(x: u32) -> u32 {
x*x
}
let y = f(5);
y*3
};
let x;
if true {
x = 1;
} else {
x = 2;
}
let x = if true { 1 } else { 2 };
MyStruct {
a: 1,
b: 1.0,
c: "".to_string()
};
(1, 1.0, "".to_string());
let t = Term::TermVar {
symbol: "".to_string()
};
match t {
Term::TermVal { value: v1 } => v1,
Term::TermVar { symbol: v1 } => v1,
Term::TermApp { f: v1, x: v2 } => "TermApp(?,?)".to_string(),
Term::TermAbs { arg: v1, body: v2 } => "TermAbs(?,?)".to_string()
};
}

@ -0,0 +1,30 @@
fn main() {
(0..10).map(|x| x*x);
(0..10).map(|x| {
fn f(y: u32) -> u32 {
y*y
}
let z = f(x+1) * f(x+2);
z*z
});
fn f<T>(g: T, x: u32) -> u32
where T: Fn(u32) -> u32
{
g(x+1) * g(x+2)
}
f(|x|{x*x}, 2);
(0..10).map(|x| x*x)
.inspect(|x|{ println!("value {}", *x) })
.filter(|x| *x<3)
.filter_map(|x| Some(x))
.fold(0, |x, y| x+y);
}

@ -0,0 +1,56 @@
//Data Type Definitions
struct PointU32
{
x: u32,
y: u32
}
struct PointF32
{
x: f32,
y: f32
}
//can be written with generics
struct Point<T>
{
x: T,
y: T
}
//Function Definitions
fn foo_u32(x: u32) -> u32
{
x*x
}
fn foo_f32(x: f32) -> f32
{
x*x
}
//can be written with generics
fn foo<T>(x: T) -> T
where T: std::ops::Mul<Output = T> + Copy
{
x*x
}
//even functions can be sent to generics
//we call these "higher order functions"
fn bar<F,T>(f: F, x: T) -> T
where F: Fn(T) -> T
{
f(x)
}
fn main()
{
PointU32 { x:1, y:1 };
PointF32 { x:1.0, y:1.0 };
Point { x:1, y:1 };
Point { x:1.0, y:1.0 };
foo_u32(1);
foo_f32(1.0);
foo(1);
foo(1.0);
bar(|x|{x}, 1);
}

@ -0,0 +1,21 @@
fn main() {
(0..10).chain(10..20);
(0..10).zip(10..20);
(0..10).enumerate();
(0..10).inspect(|x|{ println!("value {}", *x) });
(0..10).map(|x| x*x);
(0..10).filter(|x| *x<3);
(0..10).fold(0, |x,y| x+y);
for i in (0..10) {}
let v: Vec<u32> = (0..10).collect();
}

@ -0,0 +1,61 @@
#[macro_use]
extern crate metaderive;
macro_rules! my_vec_macro {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
macro_rules! my_macro_branch
{
(1 $e:expr) => (println!("mode 1: {}", $e));
(2 $e:expr) => (println!("mode 2: {}", $e));
}
enum DSLTerm {
TVar { symbol: String },
TAbs { param: String, body: Box<DSLTerm> },
TApp { f: Box<DSLTerm>, x: Box<DSLTerm> }
}
macro_rules! dsl
{
( ( $($e:tt)* ) ) => (dsl!( $($e)* ));
( $e:ident ) => (DSLTerm::TVar { symbol: stringify!($e).to_string() });
( fn $p:ident . $b:tt ) => (DSLTerm::TAbs { param: stringify!($p).to_string(), body: Box::new(dsl!($b)) });
( $f:tt $x:tt ) => (DSLTerm::TApp { f: Box::new(dsl!($f)), x: Box::new(dsl!($x)) });
}
pub trait TypeName {
fn typename() -> String;
}
#[derive(TypeName)]
struct MyStructA
{
a: u32,
b: f32
}
fn main()
{
println!("this is a macro {} {}", 1, 2);
my_vec_macro!(1, 2, 3);
my_macro_branch!(1 "abc");
my_macro_branch!(2 "def");
dsl!( a );
dsl!( fn a . a );
dsl!( f a );
dsl!( (f a) );
}

@ -0,0 +1,51 @@
struct MyObject
{
a: u32,
b: f32,
c: String
}
trait MyObjectTrait
{
fn new(a: u32, b: f32, c: String) -> Self;
fn get_a(&self) -> u32;
fn get_b(&self) -> f32;
fn get_c(&self) -> String;
}
impl MyObjectTrait for MyObject
{
fn new(a: u32, b: f32, c: String) -> Self
{
MyObject { a: a, b: b, c: c }
}
fn get_a(&self) -> u32
{
self.a
}
fn get_b(&self) -> f32
{
self.b
}
fn get_c(&self) -> String
{
self.c.clone()
}
}
trait MyObjectApply {
fn apply<T,R>(&self, f: T) -> R
where T: Fn(u32,f32,String) -> R;
}
impl MyObjectApply for MyObject {
fn apply<T,R>(&self, f: T) -> R
where T: Fn(u32,f32,String) -> R
{
f(self.a, self.b, self.c.clone())
}
}
fn main() {
}

@ -0,0 +1,52 @@
#[macro_use] extern crate cached;
#[macro_use] extern crate lazy_static;
trait Monad<A> {
fn return_(t: A) -> Self;
//:: A -> Monad<A>
fn bind<MB,B>(m: Self, f: Fn(A) -> MB) -> MB
where MB: Monad<B>;
//:: Monad<A> -> (A -> Monad<B>)) -> Monad<B>
}
fn not_curried(p1: u32, p2: u32) -> u32
{
p1 + p2
}
fn curried(p1: u32) -> Box<Fn(u32) -> u32>
{
Box::new(move |p2: u32| {
p1 + p2
})
}
cached!{
FIB;
fn fib(n: u64) -> u64 = {
if n == 0 || n == 1 { return n }
fib(n-1) + fib(n-2)
}
}
fn main()
{
let fsin = |x: f64| x.sin();
let fabs = |x: f64| x.abs();
let transform = |x: f64| fabs(fsin(x));
not_curried(1, 2);
curried(1)(2);
let immutable_v1 = 1;
//immutable_v1 = 2; //invalid
let mut mutable_v2 = 1;
mutable_v2 = 2;
let x = { println!("side effect"); 1 + 2 };
let y = ||{ println!("side effect"); 1 + 2 };
fib(30);
}

@ -0,0 +1,10 @@
[package]
name = "metaderive"
version = "1.0.0"
[dependencies]
syn = "0.12"
quote = "0.4"
[lib]
proc-macro = true

@ -0,0 +1,25 @@
#![crate_type = "proc-macro"]
extern crate proc_macro;
extern crate syn;
#[macro_use] extern crate quote;
use proc_macro::TokenStream;
#[proc_macro_derive(TypeName)]
pub fn type_name(input: TokenStream) -> TokenStream {
// Parse token stream into input AST
let ast = syn::parse(input).unwrap();
// Generate output AST
impl_typename(&ast).into()
}
fn impl_typename(ast: &syn::DeriveInput) -> quote::Tokens {
let name = &ast.ident;
quote! {
impl TypeName for #name {
fn typename() -> String {
stringify!(#name).to_string()
}
}
}
}
Loading…
Cancel
Save