Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 18485a4
Showing
11 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/target | ||
**/*.rs.bk |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "functional-programming-jargon" | ||
version = "0.1.0" | ||
authors = ["Jason Shin <visualbbasic@gmail.com>"] | ||
edition = "2018" | ||
|
||
[dependencies] | ||
partial_application = "0.1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
# Functional Programming Jargon in Rust | ||
|
||
Functional programming (FP) provides many advantages, and its popularity has been increasing as a result. | ||
However, each programming paradigm comes with its own unique jargon and FP is no exception. By providing a glossary, | ||
we hope to make learning FP easier. | ||
|
||
Where applicable, this document uses terms defined in the [Fantasy Land spec](https://github.com/fantasyland/fantasy-land | ||
|
||
The goal of this project includes understanding Rust's capability of programming in functional paradigm. | ||
|
||
__Table of Contents__ | ||
<!-- RM(noparent,notop) --> | ||
|
||
## Arity | ||
|
||
The number of arguments a function takes. From words like unary, binary, ternary, etc. | ||
This word has the distinction of being composed of two suffixes, "-ary" and "-ity." | ||
Addition, for example, takes two arguments, and so it is defined as a binary function or a function with an arity of two. | ||
Such a function may sometimes be called "dyadic" by people who prefer Greek roots to Latin. | ||
Likewise, a function that takes a variable number of arguments is called "variadic," | ||
whereas a binary function must be given two and only two arguments, currying and partial application notwithstanding (see below). | ||
|
||
```rust | ||
let sum = |a: i32, b: i32| { a + b }; // The arity of sum is 2 | ||
``` | ||
|
||
## Higher-Order Functions (HOF) | ||
|
||
A function which takes a function as an argument and/or returns a function. | ||
|
||
```rust | ||
let filter = | predicate: fn(&i32) -> bool, xs: Vec<i32> | { | ||
return xs.into_iter().filter(predicate).collect::<Vec<i32>>(); | ||
}; | ||
``` | ||
|
||
```rust | ||
let is_even = |x: &i32| { x % 2 == 0 }; | ||
``` | ||
|
||
```rust | ||
filter(is_even, vec![1, 2, 3, 4, 5, 6]); | ||
``` | ||
|
||
## Closure | ||
|
||
A closure is a scope which retains variables available to a function when it's created. This is important for | ||
[partial application](#partial-application) to work. | ||
|
||
```rust | ||
let add_to = | x: i32 | { move | y: i32 | { x + y } }; | ||
|
||
|
||
``` | ||
|
||
We can call `add_to` with a number and get back a function with a baked-in `x`. Notice that we also need to move the | ||
ownership of the y to the internal lambda. | ||
|
||
```rust | ||
let add_to_five = add_to(5); | ||
``` | ||
|
||
In this case the `x` is retained in `add_to_five`'s closure with the value `5`. We can then call `add_to_five` with the `y` | ||
and get back the desired number. | ||
|
||
```rust | ||
add_to_five(3); // => 8 | ||
``` | ||
|
||
Closures are commonly used in event handlers so that they still have access to variables defined in their parents when they | ||
are eventually called. | ||
|
||
__Further reading__ | ||
* [Lambda Vs Closure](http://stackoverflow.com/questions/220658/what-is-the-difference-between-a-closure-and-a-lambda) | ||
* [How do JavaScript Closures Work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) | ||
|
||
## Partial Application | ||
|
||
Partially applying a function means creating a new function by pre-filling some of the arguments to the original function. | ||
|
||
To achieve this easily, we will be using a [partial application crate](https://crates.io/crates/partial_application) | ||
|
||
```rust | ||
#[macro_use] | ||
extern crate partial_application; | ||
|
||
fn foo(a: i32, b: i32, c: i32, d: i32, mul: i32, off: i32) -> i32 { | ||
(a + b*b + c.pow(3) + d.pow(4)) * mul - off | ||
} | ||
|
||
let bar = partial!( foo(_, _, 10, 42, 10, 10) ); | ||
|
||
assert_eq!( | ||
foo(15, 15, 10, 42, 10, 10), | ||
bar(15, 15) | ||
); // passes | ||
``` | ||
|
||
Partial application helps create simpler functions from more complex ones by baking in data when you have it. | ||
Curried functions are automatically partially applied. | ||
|
||
__Further reading__ | ||
* [Partial Application in Haskell](https://wiki.haskell.org/Partial_application) | ||
|
||
|
||
## Currying | ||
|
||
The process of converting a function that takes multiple arguments into a function that takes them one at a time. | ||
|
||
Each time the function is called it only accepts one argument and returns a function that takes one argument until all arguments are passed. | ||
|
||
|
||
```rust | ||
fn add(x: i32) -> impl Fn(i32)-> i32 { | ||
return move |y| x + y; | ||
} | ||
|
||
let add5 = add(5); | ||
add5(10); // 15 | ||
``` | ||
|
||
__Further reading__ | ||
* [Currying in Rust](https://hashnode.com/post/currying-in-rust-cjpfb0i2z00cm56s2aideuo4z) | ||
|
||
## Purity | ||
|
||
A function is pure if the return value is only determined by its input values, and does not produce side effects. | ||
|
||
```rust | ||
let greet = |name: &str| { format!("Hi! {}", name) }; | ||
|
||
greet("Jason"); // Hi! Jason | ||
``` | ||
|
||
As opposed to each of the following: | ||
|
||
```rust | ||
let name = "Jason"; | ||
|
||
let greet = || -> String { | ||
format!("Hi! {}", name) | ||
}; | ||
``` | ||
|
||
The above example's output is based on data stored outside of the function... | ||
|
||
```rust | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#[test] | ||
fn arity() { | ||
let sum = |a: i32, b: i32| { a + b }; | ||
let result = sum(1, 2); | ||
assert_eq!(result, 3); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#[test] | ||
fn closure() { | ||
let add_to = | x: i32 | { move | y: i32 | { x + y } }; | ||
|
||
let add_to_five = add_to(5); | ||
|
||
assert_eq!(add_to_five(3), 8); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#[test] | ||
fn currying() { | ||
fn add(x: i32) -> impl Fn(i32)-> i32 { | ||
return move |y| x + y; | ||
} | ||
|
||
let add5 = add(5); | ||
let result = add5(10); | ||
assert_eq!(result, 15); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#[test] | ||
fn hof() { | ||
let filter = | predicate: fn(&i32) -> bool, xs: Vec<i32> | { | ||
// A good Reddit post on how Filter works https://www.reddit.com/r/rust/comments/3bmua6/can_someone_help_me_understand_stditerfilter/ | ||
return xs.into_iter().filter(predicate).collect::<Vec<i32>>(); | ||
}; | ||
|
||
let is_even = |x: &i32| { x % 2 == 0 }; | ||
|
||
let result = filter(is_even, vec![1, 2, 3, 4, 5, 6]); | ||
|
||
assert_eq!(result, vec![2, 4, 6]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#[macro_use] | ||
extern crate partial_application; | ||
|
||
mod arity_example; | ||
mod hof_example; | ||
mod closure_example; | ||
mod partial_application_example; | ||
mod currying_example; | ||
mod purity_example; | ||
|
||
fn main() { | ||
println!("Hello, world!"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#[test] | ||
fn partial_application() { | ||
fn foo(a: i32, b: i32, c: i32, d: i32, mul: i32, off: i32) -> i32 { | ||
(a + b*b + c.pow(3) + d.pow(4)) * mul - off | ||
} | ||
|
||
let bar = partial!(foo(_, _, 10, 42, 10, 10)); | ||
|
||
assert_eq!( | ||
foo(15, 15, 10, 42, 10, 10), | ||
bar(15, 15) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#[test] | ||
fn purity() { | ||
let greet = |name: &str| { format!("Hi! {}", name) }; | ||
|
||
assert_eq!("Hi! Jason", greet("Jason")); | ||
} | ||
|
||
#[test] | ||
fn impure() { | ||
let name = "Jason"; | ||
|
||
let greet = || -> String { | ||
format!("Hi! {}", name) | ||
}; | ||
|
||
assert_eq!("Hi! Jason", greet()); | ||
} | ||
|
||
#[test] | ||
fn impure2() { | ||
let mut greeting = h | ||
} |