# .title[Rust and Haskell] # .subtitle[sitting in a tree] .flex[  .flex-helper[ Lisa '[lislis](https://lislis.de/)' Passing [Lambda.World Cรกdiz](http://cadiz.lambda.world/) 2018]] --- # $ whoami -- Hi, I'm Lisa ๐ -- Web dev, game jammer, wannabe digital artist, fp enthusiast -- From a dynamically typed language background (JS, Ruby) -- Came to fp through Clojure/Script -- Started learning Rust 1.5 years ago --- class: center, middle  --- class: contain background-image: url(img/rust-lang-website.png) --- class: contain background-image: url(img/rust-lang-inference.png) --- class: contain background-image: url(img/rust-lang-pattern.png) --- class: contain background-image: url(img/rust-lang-traits.png) --- class: contain background-image: url(img/rust-lang-zero.png) --- # Let's see -- - type inference - pattern matching - trait-based generics - zero-cost abstractions -- ### Could make a pretty good fp talk ๐ค --- class: center, middle, invert # Type inference --- class: middle background-image: url(img/haskell.svg) > Did someone say **type inference**? --- layout: true ## Type inference in Haskell --- -- ```haskell doubleMe x = x * 2 ``` --- ```haskell doubleMe x = x * 2 doubleMe 8 ``` ```haskell 16 ``` -- Haskell infers that this can only work with numbers. -- ```haskell doubleMe "this is a trick!" doubleMe [] ``` -- ```bash ERROR! ``` -- We get an error for everything else. --- This works with lists, too! -- ```haskell doubleFirstOfList xs = head xs * 2 ``` -- ```haskell doubleFirstOfList [239, 3482, 23, 23] ``` -- ```bash 478 ``` --- We don't have to annotate types, but it's nice when we do. -- ```haskell doubleMe' Int -> Int doubleMe' x = x * 2 ``` -- ```haskell doubleFirstOfList' :: [Int] -> Int doubleFirstOfList' xs = head xs * 2 ``` --- layout: false class: middle background-image: url(img/rust-logo.jpg) > What about Rust? --- layout: true ## Type inference in Rust --- -- - Types are inferred when possible -- ```rust fn main() { let elem = 5; let doubleElem = elem * 2; println!("{}", doubleElem); } ``` -- ```bash 10 ``` --- ```rust fn main() { let vector = vec![2, 16, 348]; let double_first_of_vec = vector[0] * 2; println!("{}", double_first_of_vec); } ``` -- ```bash 4 ``` --- .one-p[ Function params and return values have to always be annotated!] -- ```rust fn double_first_of_vec(v:Vec
) -> u32 { v[0] * 2 } fn main() { let vector = vec![2, 16, 348]; println!("{}", double_first_of_vec(vector)); } ``` -- ```bash 4 ``` --- layout: false class: center, middle, invert # Trait-based generics --- ## What are generics in Rust? -- An abstract stand-in for a concrete type -- ```rust fn first_and_last
(v: &Vec
) -> Vec<&T> { } ``` --- ## What are generics in Rust? An abstract stand-in for a concrete type ```rust fn first_and_last
(v: &Vec
) -> Vec<&T> { vec![v.first().unwrap(), v.iter().last().unwrap()] } ``` -- ```rust fn main() { let nums = vec![2, 16, 348]; println!("{:?}", first_and_last(&nums)); let strings = vec!["Hello", "a", "foo", "World"]; println!("{:?}", first_and_last(&strings)); } ``` -- ```bash [2, 348] ["Hello", "World"] ``` --- class: middle background-image: url(img/haskell.svg) > Oh, did you mean **type variables**? --- ## Type variables in Haskell -- ```haskell firstAndLast :: [a] -> [a] firstAndLast xs = [head xs, last xs] ``` -- ```haskell firstAndLast [45, 28, 645, 23] ``` ```bash [45, 23] ``` --- ## What are Traits in Rust? -- .one-p[ Traits define behaviour that Types can implement. ] -- Example `Display` Trait for user facing string output. --- class: contain background-image: url(img/display-trait.png) --- ### Implementing `Display` on a type -- ```rust use std::fmt; struct Point { x: i32, y: i32 } ``` --- ### Implementing `Display` on a type ```rust use std::fmt; struct Point { x: i32, y: i32 } impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) } } ``` --- ### Implementing `Display` on a type ```rust use std::fmt; struct Point { x: i32, y: i32 } impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) } } let p = Point { x: 0, y: 0 }; println!("The point is: {}", p); ``` -- ```bash The point is: (0, 0) ``` --- class: middle background-image: url(img/haskell.svg) > Sounds a lot like **type classes** --- ## Type classes in Haskell -- Let's look at the `Show` type class -- ```haskell data Point = Point { x :: Int , y :: Int } deriving (Show) ``` -- ```haskell let p1 = Point 2 3 show p1 ``` -- ```bash Point {x = 2, y = 3} ``` --- Alternatively we can make a function ```haskell display :: Point -> String display (Point {x=x, y=y}) = "The point is (" ++ show x ++ "," ++ show y ++")" ``` -- ```haskell let p = Point 0 0 display p ``` -- ```bash The point is (0, 0) ``` --- ### Trait bounds! -- ```rust // Rust use std::fmt::Display; fn shout_out
(s: T) -> String { format!("{}!!!!!!!!!", s) } fn main() { println!("{}", shout_out("Uuuuh")); } ``` -- ### Class constraints! -- ```haskell -- Haskell shoutOut :: (Show a) => a -> String shoutOut x = (show x) ++ "!!!!!!!!!!" shoutOut "Yeah" ``` --- class: center, middle, invert # Pattern matching --- class: middle background-image: url(img/haskell.svg) > Did someone say **pattern matching**? --- ## Pattern matching in Haskell -- ```haskell data Shape = Circle Float Float Float | Rectangle Float Float Float Float surface :: Shape -> Float surface (Circle _ _ r) = pi * r ^ 2 surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1) ``` -- ```haskell surface $ Circle 10 10 10 ``` -- ```bash 314.15927 ``` --- class: middle background-image: url(img/rust-logo.jpg) > And in Rust? --- ## Pattern matching in Rust -- ```rust use std::f32::consts::PI; struct Circle(f32, f32, f32); struct Rectangle(f32, f32, f32, f32); enum Shape { Circle(f32, f32, f32), Rectangle(f32, f32, f32, f32) } ``` --- ## Pattern matching in Rust ```rust use std::f32::consts::PI; struct Circle(f32, f32, f32); struct Rectangle(f32, f32, f32, f32); enum Shape { Circle(f32, f32, f32), Rectangle(f32, f32, f32, f32) } fn surface(s: Shape) -> f32 { match s { Shape::Circle(_, _, r) => ( PI * r.powf(2.0) ), Shape::Rectangle(x1, y1, x2, y2) => { (x2 - x1).abs() * (y2 - y1).abs() }, } } ``` --- ## Pattern matching in Rust ```rust fn main() { let circle = Shape::Circle(10.0, 10.0, 10.0); println!("{:?}", surface(circle)); } ``` -- ```bash 314.15927 ``` --- class: center, middle, invert # Zero-cost abstractions --- class: middle background-image: url(img/rust-logo.jpg) >.one-p[ Using higher level concepts at no additional performance cost!] --- class: middle, center Example ## Higher order functions --- ## Higher order functions ## in Haskell -- Like map -- ```haskell map (+3) [1,5,3,1,6] ``` -- ```bash [4,8,6,4,9] ``` -- or filter -- ```haskell filter (>3) [1,5,3,2,1,6,4,3,2,1] ``` -- ```bash [5,6,4] ``` --- class: middle background-image: url(img/rust-logo.jpg) > What about Rust? --- ## About functions in Rust .small[(pt 1)] -- Function declarations in Rust are statements. Function calls are expressions. -- .one-p[ Statements cannot be evaluated and therefore not be assigned to variables nor used as an arbitrary value.] -- Expressions can be. --- ## About functions in Rust .small[(pt 2)] -- .one-p[ A function's name becomes part of its type, therefore two functions with the same signature are still different.] -- .one-p[ Dynamically creating functions and passing or returning them is not (easily) possible because types need to annotated beforehand.] --- class: middle background-image: url(img/rust-logo.jpg) > Wait, no higher order functions in Rust? -- > Well, not like this... --- class: middle background-image: url(img/rust-logo.jpg) > But there is a another way! --- ## Closures in Rust -- Closures are anonymous functions that can capture their environment. -- Their declarations can be stored in variables. -- They don't need type annotations for params or return values (Types are inferred on first use). -- Every closure has its own type but implements one of the traits `Fn`, `FnMut`, `FnOnce`. This can be used with trait bounds when defining structs that hold closures. --- ## Using closures with `Iterator`s -- ```rust fn main() { let vmap: Vec
= vec![1, 5, 3, 1, 6] .into_iter() .map(|x| x + 3) .collect(); } ``` --- ## Using closures with `Iterator`s ```rust fn main() { let vmap: Vec
= vec![1, 5, 3, 1, 6] .into_iter() .map(|x| x + 3) .collect(); let vfilter: Vec
= vec![1,5,3,2,1,6,4,3,2,1] .into_iter() .filter(|x| x > &3) .collect(); println!("{:?}", vmap); println!("{:?}", vfilter); } ``` -- ```bash [4, 8, 6, 4, 9] [5, 6, 4] ``` --- class: middle background-image: url(img/rust-logo.jpg) >.one-p[ ### Zero-cost abstractions Using higher level concepts at no additional performance cost!] --- class: center, middle _phew_ -- That was a lot. --- # Rust and Haskell -- Rust is not a functional language, but it has learned a lot of good things from Haskell and the functional world. --- ## More nice things! -- - [Rust REPL RFC](https://github.com/rust-lang/rfcs/issues/655) --- class: bg-right background-image: url(img/hkt.jpg) ## More nice things! - [Rust REPL RFC](https://github.com/rust-lang/rfcs/issues/655) - [Generic associated types RFC](https://github.com/rust-lang/rfcs/pull/1598) .one-p[ (formerly known as associated type constructors)] --- class: middle, center ## Where are the trees? I thought of a pun when writing the talk title, but decided the pun doesn't work when writing the talk
ยฏ\_(ใ)_/ยฏ
--- ## Thank you! .no-bullets[ - ๐ง mail@lislis.de - ๐ lislis@toot.cat - ๐ https://github.com/lislis - ๐ฝ๏ธ https://lislis.de/talks/lambda-world-2018/] ### Resources - [The Rust Programming Language](https://doc.rust-lang.org/book/second-edition/index.html) - [Rust by Example](https://doc.rust-lang.org/rust-by-example/) - [Learn you a Haskell](http://learnyouahaskell.com/chapters)