Chapter 1 Draft
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,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…
Reference in New Issue