47
HEY! There’s OCaml In My Rust! Kel Cecil @praisechaos

Hey! There's OCaml in my Rust!

Embed Size (px)

Citation preview

Page 1: Hey! There's OCaml in my Rust!

HEY!There’s OCaml In My Rust!Kel Cecil@praisechaos

Page 2: Hey! There's OCaml in my Rust!

I ❤ Languages

Page 3: Hey! There's OCaml in my Rust!

Incredible Shrinking Operating SystemSteve JonesDevOps Days 2015

Page 4: Hey! There's OCaml in my Rust!

OCaml is pretty cool!

Page 5: Hey! There's OCaml in my Rust!

It's a functional programming language...

# let double x = x * 2 in List.map double [ 1; 2; 3 ];;- : int list = [2; 4; 6]

• OCaml is an almost pure functional programming language by default.

• Functions are first-class citizens.

Page 6: Hey! There's OCaml in my Rust!

... and an imperative programming language...

let update_collectable_value order new_value = order.old_value <- order.current_value; order.current_value <- new_value; order

• It can be convenient to be able to code in the imperative style.

• OCaml includes imperative constructs like for and while loops.

Page 7: Hey! There's OCaml in my Rust!

... and an object-oriented language!class ['a] queue init = object val mutable q: 'a list = init

method enqueue item = q <- q @ itemend;;

• OCaml can also be object-oriented if needed.

Page 8: Hey! There's OCaml in my Rust!

OCaml powers some pretty sweet stuff.

• MirageOS: Unikernel tech recently acquired by Docker

• Flow: A static type checker for JavaScript• Hack: A programming languages for Facebook's

HHVM• and...

Page 9: Hey! There's OCaml in my Rust!

Rust's first compiler!• rustboot was written in OCaml• Replaced for Rust 0.7

Page 10: Hey! There's OCaml in my Rust!

Rust is pretty excellent too!• Guaranteed Memory Safety• Threads without data races• Incredibly fast• Crazy awesome potential

Page 11: Hey! There's OCaml in my Rust!

Rust was inspired by OCaml in a few interesting ways!

Page 12: Hey! There's OCaml in my Rust!

Let's start with a simple, imperative OCaml program

• Define a type named collectable_value that olds the previous value and current value of an item.

• Provide a function to update the current value and update the old value.

• Have a "main" function to create the record and update the value.

Page 13: Hey! There's OCaml in my Rust!

Starting with our typetype collectable_value = { mutable old_value: float; mutable current_value: float;}

• A record is a collection of values stored together as a data type.

• Values are immutable by default but can be marked as mutable.

Page 14: Hey! There's OCaml in my Rust!

Adding our first functionlet update_collectable_value collectable new_value = collectable.old_value <- collectable.current_value; collectable.current_value <- new_value; collectable

• Define a function with a let-binding.• Accepts a collectablevalue record (collectable) and a

float (newvalue).• Updates and returns the record.

Page 15: Hey! There's OCaml in my Rust!

Adding a "main"let _ = let pinball_machine = { old_value = 0.0; current_value = 800.00; } in update_collectable_value pinball_machine 900.0

• Underscore discards the return value.• This let-binding allows us to execute code at the top

level.

Page 16: Hey! There's OCaml in my Rust!

Anything seem a little Rust-y to you?type collectable_value = { mutable old_value: float; mutable current_value: float;}

let update_collectable_value order new_value = order.old_value <- order.current_value; order.current_value <- new_value; order

let _ = let pinball_machine = { old_value = 0.0; current_value = 800.00; } in update_collectable_value pinball_machine 900.0

Page 17: Hey! There's OCaml in my Rust!

Semicolon Separation in OCamllet update_collectable_value collectable new_value = collectable.old_value <- collectable.current_value; collectable.current_value <- new_value; collectable

• Notice the semi-colons separating the expressions?• The last expression is the return value for the

function.• Look familiar?

Page 18: Hey! There's OCaml in my Rust!

Statements in Rustfn greeting() -> String { let greeting = "Hello, there!"; String::from(greeting) // Return value from fn}

• Rust code is mostly statements.• Most common statements are

• declaring a variable• using an expression with a semi-colon

• Last expression omitting the semi-colon is returned.

Page 19: Hey! There's OCaml in my Rust!

What is Type Inference?• Automatic deduction of the data type of an

expression.

Page 20: Hey! There's OCaml in my Rust!

Rust's Type Inference// Rust knows that name is a String.let name = "Kel!"

• Rust's type inference is loosely based on the Hindley-Milner algorithm4.

• Extensions were added to use accommodate subtyping.

4 https://github.com/rust-lang/rust/blob/master/src/librustc/infer/README.md

Page 21: Hey! There's OCaml in my Rust!

OCaml's Type Inference(* OCaml also knows this is a string. *)let name = "Kel!"

• ML originally used the Hindley-Milner algorithm.• OCaml's implementation works through solving

constraints.• Tons of research hours poured into their

algorithm(s)5

5 https://www.cis.upenn.edu/~sweirich/icfp-plmw15/slides/pottier.pdf

Page 22: Hey! There's OCaml in my Rust!

Workshop: Binary Search Tree• Follow along in your IDEs!• Learn about binary search trees here:

• https://en.wikipedia.org/wiki/Binary_search_tree• Check out the examples

• https://github.com/kelcecil/rust-ocaml-workshop

Page 23: Hey! There's OCaml in my Rust!

Building our Tree StructureOCaml, then Rust.

Page 24: Hey! There's OCaml in my Rust!

Tree in OCaml

type tree;;

• Types in OCaml are defined with the type keyword.

Page 25: Hey! There's OCaml in my Rust!

Tree in OCaml

type tree = Empty;;

• We need to represent a node that does not exist.• We'll represent this as Empty.

Page 26: Hey! There's OCaml in my Rust!

Tree in OCaml

type tree = | Empty | Node;;

• We also want to represent a node that exists.• We'll represent this as node.

Page 27: Hey! There's OCaml in my Rust!

Tree in OCaml

type 'a tree = | Empty | Node of 'a * 'a tree * 'a tree;;

• Our node must have a key, a left child, and a right child.

• Node now contains generic 'a that is our key.• We also have two values of tree presenting our left

and right leaves.

Page 28: Hey! There's OCaml in my Rust!

Algebraic Data Types• Composite type formed from other types• Common types of Algebraic Types

• Product Types• Sum Types

Page 29: Hey! There's OCaml in my Rust!

Product Types• Compound types in a structure• Operands of the product are types• Structure is determined by fixed order of operands

Page 30: Hey! There's OCaml in my Rust!

(* Record *)type person = {name: string; age: int};;let kel = {name = "Kel"; age = 30};;

(* Tuple *)let next_obsession = ("Dead Rising 4", 59.99);;

Tuples and records are product types in OCaml

Page 31: Hey! There's OCaml in my Rust!

let my_love = ("Rust", 9001)

• Tuples are product types in Rust• There's also the unit () type

• Tuple with no operands.

Page 32: Hey! There's OCaml in my Rust!

Sum Typestype 'a tree = | Empty | Node of 'a * 'a tree * 'a tree;;

• Multiple classes of values called variants.• Each class has it's own constructor.• Class represents it's own concept

Page 33: Hey! There's OCaml in my Rust!

Tree in Rust

enum Tree { Empty}

• Algebraic data types are enums in Rust.• We start with defining Empty.

Page 34: Hey! There's OCaml in my Rust!

enum Tree<T>{ Empty, Node(T, Box<Tree<T>>, Box<Tree<T>>)}

• Node is a generic variable for the key, a left leaf, and a right leaf.

• Recursive structures must be boxed1.• We want the size of the Tree to be bounded.• Pointer using Box allocates memory on the heap.

1 https://doc.rust-lang.org/std/boxed/

Page 35: Hey! There's OCaml in my Rust!

Recap: Rust and OCaml Tree Structures6

type 'a tree = | Empty | Node of 'a * 'a tree * 'a tree;;

enum Tree<T>{ Empty, Node(T, Box<Tree<T>>, Box<Tree<T>>)}

6 https://github.com/kelcecil/rust-ocaml-workshop/tree/master/workshop/01-structure

Page 36: Hey! There's OCaml in my Rust!

Writing a depth function

Page 37: Hey! There's OCaml in my Rust!

depth (OCaml using Pattern Matching)let rec depth tree = match tree with | Empty -> 0 | Node(_, left, right) -> 1 + max (depth left) (depth right);;

• let defines a variable or function in OCaml.• rec denotes a recursive function.• The match keyword matches by data type.

Page 38: Hey! There's OCaml in my Rust!

depth (OCaml using function)let rec depth = function | Empty -> 0 | Node(_, left, right) -> 1 + max (depth left) (depth right);;

• OCaml functions can also be defined using the function keyword.

• function has built in pattern matching for types.• This syntax is a bit more concise.

Page 39: Hey! There's OCaml in my Rust!

Unit Test for depth (OCaml)open OUnit

(* tree type here *)(* depth function here *)

let test_tree = Node(5, Node(3, Empty, Empty), Empty)

let tree_depth _ = assert_equal 2 (depth test_tree)

let suite = "Binary Tree Tests" >::: ["tree_depth" >:: tree_depth]

let _ = run_test_tt_main suite

Page 40: Hey! There's OCaml in my Rust!

Running OCaml Testsocamlfind ocamlc -package oUnit -linkpkg -o <output_binary> <source_file>

Page 41: Hey! There's OCaml in my Rust!

depth (Rust)impl<T> Tree<T> where T: PartialOrd{ fn depth(&self) -> usize { match *self { Tree::Empty => 0, Tree::Node(_, ref left, ref right) => 1 + max(left.depth(), right.depth()) } }}

• Restricting our generic to PartialOrd lets us choose our key type similarly to OCaml.

Page 42: Hey! There's OCaml in my Rust!

Unit Test for depth (Rust)

#[test]fn depth_test() { let tree = Tree::Node(5, Box::new( Tree::Node(4,Box::new(Tree::Empty), Box::new(Tree::Empty) )), Box::new(Tree::Empty)); assert!(tree.depth() == 2)}

Page 43: Hey! There's OCaml in my Rust!

Running Rust Unit Tests

rustc --test <source_file>

Page 44: Hey! There's OCaml in my Rust!

tl;dr• OCaml's inspiration for Rust can been seen in:

• Semicolon Statement Separation• Type Inference• Algebraic Data Types• Pattern Matching

• Rust and OCaml are both totally awesome.

Page 45: Hey! There's OCaml in my Rust!

Time for you to try!• Adjust the our tree implementations to hold values.• Write insert functions for OCaml and Rust!• Write member functions for OCaml and Rust!

Page 46: Hey! There's OCaml in my Rust!

Stumped? No problem.• https://github.com/kelcecil/rust-ocaml-workshop• Clone the repository and experiment!• Check out the other random examples in the

repository.• Ask for help!

Page 47: Hey! There's OCaml in my Rust!

Branching in OCamlOCaml has an if statement like so2:

if <boolean_condition> then <expression>else if <boolean_condition> then <expression>else <expression>

2 https://ocaml.org/learn/tutorials/ifstatementsloopsandrecursion.html