-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Deploy hds/lunch.rs to hds/lunch.rs:gh-pages
- Loading branch information
GitHub Actions
committed
Oct 25, 2024
0 parents
commit b7e8e06
Showing
34 changed files
with
2,550 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
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,3 @@ | ||
<!doctype html> | ||
<title>404 Not Found</title> | ||
<h1>404 Not Found</h1> |
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 @@ | ||
lunch.rs |
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,76 @@ | ||
<!DOCTYPE html> | ||
<html lang="en_GB"> | ||
|
||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
|
||
<title>About Rust for Lunch - Rust for Lunch</title> | ||
|
||
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> | ||
<link rel="alternate" type="application/rss+xml" title="Rust for Lunch Meet-ups" href="/rss.xml" /> | ||
<link rel="icon" href="/favicon.ico" type="image/x-icon"> | ||
|
||
<link rel="stylesheet" href="/css/lunch.css"> | ||
</head> | ||
|
||
<body> | ||
<div class="masthead" role="navigation"> | ||
<div class="container"> | ||
<nav> | ||
<a class="nav-item" href="/">lunch</a> | ||
<a class="nav-item" href="/about/">about</a> | ||
</nav> | ||
</div> | ||
</div> | ||
<div class="container" role="main"> | ||
|
||
|
||
<div class="post"> | ||
<h1><a href="https://lunch.rs/about/">About Rust for Lunch</a></h1> | ||
|
||
<div><p>Rust for Lunch is an online-only Rust meet scheduled to fit into a lunch break.</p> | ||
<p>The main part of each meet-up will be short enough to fit into a 1 hour lunch | ||
slot and the time is chosen to be a feasible lunch time.</p> | ||
<p>The first meet-up will be scheduled around European and African midday and | ||
early afternoon.</p> | ||
<h2 id="code-of-conduct">Code of Conduct</h2> | ||
<p>The Rust for Lunch project adheres to the <a href="https://github.com/rust-lang/rust/blob/master/CODE_OF_CONDUCT.md">Rust Code of Conduct</a>. This | ||
describes the <em>minimum</em> behavior expected from all contributors and as well as | ||
attendees.</p> | ||
<p>Instances of violations of the Code of Conduct can be reported by contacting | ||
the Hayden at his personal email address | ||
<a href="mailto:[email protected]">[email protected]</a>.</p> | ||
<h2 id="disclaimer">Disclaimer</h2> | ||
<p>Rust for Lunch is not associated with or endorsed by neither the | ||
<a href="https://www.rust-lang.org/">Rust Project</a> nor the | ||
<a href="https://foundation.rust-lang.org/">Rust Foundation</a>.</p> | ||
<h2 id="social">Social</h2> | ||
<p>We have social spaces where meet-up details are announced. You're also welcome | ||
to join and discuss whatever topic interests you, especially Rust of course.</p> | ||
<ul> | ||
<li>Matrix room: <a href="https://matrix.to/#/#rust-for-lunch:matrix.org">#rust-for-lunch:matrix.org</a></li> | ||
<li>Discord server: <a href="https://discord.gg/DbcWXPR5aq">discord.gg/DbcWXPR5aq</a></li> | ||
</ul> | ||
<h2 id="contributing">Contributing</h2> | ||
<p>We would love to have more people involved in the Rust for Lunch meetup.</p> | ||
<p>Please get in touch with Hayden if you would like to speak at a meet-up.</p> | ||
<p>If you would like to contribute in another way, either get in touch or | ||
open an issue on the | ||
<a href="https://github.com/hds/lunch.rs">lunch.rs GitHub project</a>.</p> | ||
<h2 id="contact">Contact</h2> | ||
<p>You can get in touch with Hayden at his | ||
<a href="mailto:[email protected]">personal email address</a>. See the <a href="https://hegdenu.net/about/#contact">hegdenu.net about page</a> for more ways.</p> | ||
</div> | ||
</div> | ||
|
||
|
||
<div class="footer" role="footer"> | ||
<div class="separator"></div> | ||
<p><span class="current-year">2023</span>, Hayden Stainsby.</p> | ||
</div> | ||
</div> | ||
|
||
</body> | ||
|
||
</html> |
Binary file added
BIN
+258 KB
content/2023-10-31/Abusing_the_Type_System_for_Fun_and_for_Profit-0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+3.87 MB
content/2023-10-31/Abusing_the_Type_System_for_Fun_and_for_Profit.pdf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,224 @@ | ||
--- | ||
title: Parsing command line options with Category Theory | ||
author: Michael Baykov | ||
--- | ||
|
||
# Rust types and functions | ||
|
||
Two of the main building blocks in Rust are functions and values. Values come in different | ||
types, functions let you to convert between them. Not all functions are the same though, some | ||
depend on the inputs only and only produce some resulting value, some - do something else. | ||
|
||
Functions of first type are called pure and they are great - they are easy to work with, easy | ||
to test, easy to reason about. | ||
|
||
```rust | ||
let a = 3; | ||
|
||
fn inc(v: usize) -> usize [ | ||
v + 1 | ||
} | ||
|
||
let b = inc(a) | ||
``` | ||
|
||
<!-- end_slide --> | ||
|
||
# Pure functions, side effects | ||
|
||
Functions compose - that is given two functions: from A to B and from B to C you can make a | ||
function from A to C. We can think of a function as always taking a value in and always | ||
producing a value. If it takes none - it's `()`, if it takes multiple values - it's a tuple. | ||
Same with results - use tuples or `()`. | ||
|
||
![](pic1.jpg) | ||
|
||
<!-- end_slide --> | ||
|
||
# Parsers | ||
|
||
Then there's parsers. A typical shape of a parser looks like this | ||
|
||
```rust | ||
Fn(I) -> Result<(I, T), Error> | ||
``` | ||
|
||
```rust | ||
Fn(&mut I) -> Result<T, Error> | ||
``` | ||
|
||
First doesn't compose well, second - contains side effects. let's look into ways to manage | ||
those effects. | ||
|
||
<!-- end_slide --> | ||
|
||
# Modeling side effects | ||
|
||
We start with the easiest possible side effects - a computation that can fail. In Rust you'd | ||
use `Option` or `Result` for that. | ||
|
||
```rust | ||
fn bad(i: Option<u8>) -> Option<u8> { | ||
match i { | ||
None => Some(42), | ||
Some(42) => Some(1), | ||
_ => None | ||
} | ||
} | ||
``` | ||
|
||
```rust | ||
fn good(i: Option<u8>) -> Option<u8> { | ||
match i { | ||
None => None, | ||
Some(i) => Some(i + 3), | ||
} | ||
} | ||
``` | ||
|
||
They are both valid functions, but for "bad" case pure computation and effects are mixed | ||
together, while in "good" one - effects are separate | ||
|
||
<!-- end_slide --> | ||
|
||
# Functor | ||
|
||
Second function represents something called a `Functor` | ||
|
||
Like pure functions Functors are also great. If you have something that obeys Functor laws - | ||
you can plug any pure computation inside and it will just work, easy to test too. Rust comes | ||
with a bunch of Functors: `Option::map`, `Result::map`. `Iterator<Item = A>::map` is also a | ||
functor | ||
|
||
Functor must preserve identity morphisms and compositions of morphisms: | ||
|
||
`a.map(id) == a`, `a.map(f).map(g) == a.map(g . f)`. But that's just a complicated way of | ||
saying - "don't throw away information and maintain the computation shape". In the previous | ||
example "bad" throws away and invents stuff, "good" does great. | ||
|
||
In general I'm going to use a notation `F<A>` for types and `map f` for arrows, where `F` is a | ||
type or a trait concrete for this Functor, and `A` is some variable Functor knows nothing about | ||
so it can only apply morphisms like `Fn(A) -> B` and nothing else | ||
|
||
![](pic2.png) | ||
|
||
<!-- end_slide --> | ||
|
||
# Applicative | ||
|
||
Before I said we'll assume functions take a single argument and for multiple - we make a tuple. | ||
|
||
Consider two values `A` and `B` and a function `f: Fn((A, B)) -> C` and think how corresponding | ||
Functor might look like. A tuple is `(F<A>, F<B>)` and there's no corresponding pure | ||
functions. Not good. We need to introduce one more bit of abstraction. | ||
|
||
**Suppose `F` is a functor, then for two computations** | ||
**`F<A>` and `F<B>` we can make `Fn((F<A>, F<B>)) -> F<(A, B)>`** | ||
|
||
For `Option` this is `Option::zip`, for `Result`.... It can also be `zip`, as long as errors | ||
agree, but for some reason it's missing. There's also `Iterator::zip` that does it for two | ||
iterators. Same idea | ||
|
||
[functor like category, `(A, B) -> C` on the left, `(F<A>, F<B>) -> F<(A, B)> -> F<C>` on the right] | ||
|
||
<!-- end_slide --> | ||
|
||
# Alternative | ||
|
||
Getting somewhere. We know that the parser might fail so we must introduce some notion of | ||
failure. For `Option` this is `None`, for `Result` this is `Err`. | ||
|
||
We can add two functions to our abstract interface | ||
|
||
``` | ||
pure: Fn(T) -> F<T> | ||
fail: Fn(E) -> F<T> | ||
``` | ||
|
||
And now that we know that some computation can fail - we want something to be able to try | ||
several of them | ||
|
||
```rust | ||
alt: Fn(F<T>, F<T>) -> F<T> | ||
``` | ||
|
||
In Rust this is `Option::or` and `Result::or` (and their variants) | ||
|
||
<!-- end_slide --> | ||
|
||
# Making a simple parser | ||
|
||
Now that we have all the basic methods we can look into making something with the parser | ||
|
||
```rust | ||
map: Fn(F<A>, Fn(A) -> B) -> F<B> | ||
zip: Fn(F<A>, F<B>) -> F<(A, B)> | ||
pure: Fn(A) -> F<A> | ||
fail: Fn(E) -> F<A> | ||
alt: Fn(F<A>, F<A>) -> F<A> | ||
``` | ||
|
||
It doesn't matter which version of the parser we begin with - | ||
|
||
```rust | ||
Fn(I) -> Result<(I, T), Error> = ... | ||
Fn(&mut I) -> Result<T, Error> = ... | ||
``` | ||
|
||
```rust | ||
struct Parser<T>(Box<Fn(&mut Args)> -> Result<T, Error>); | ||
``` | ||
|
||
```rust | ||
trait Parser<A> { | ||
fn map(self, impl Fn(A) -> B) -> impl Parser<B> {..} | ||
fn zip(self, other: impl Parser<B>) -> impl Parser<(A, B)> {..} | ||
... | ||
} | ||
``` | ||
|
||
<!-- end_slide --> | ||
|
||
# Methods we can implement | ||
|
||
```rust | ||
trait Parser<A> { | ||
// Required to compose | ||
|
||
fn map(self, f: impl Fn(F<A>, Fn(A) -> B) -> impl Parser<B> {..} | ||
fn zip(self, other: impl Parser<B>) -> impl Parser<(A, B)> {..} | ||
fn pure(val: A) -> impl Parser<A> {..} | ||
fn fail(message: &'static str) -> impl Parser<A> {..} | ||
fn alt(self, other: impl Parser<A>) -> impl Parser<A> {..} | ||
|
||
// Convenience | ||
fn optional(self) -> impl Parser<Option<A>> {..} | ||
fn many(self) -> impl Parser<Vec<A>> {..} | ||
fn some(self, error: &'static str) -> impl Parser<Vec<A>> {..} | ||
fn collect<C: FromIterator<A>>(self) -> impl Parser<C> {..} | ||
fn parse(self, impl Fn(A) -> Result<B, E>) -> impl Parser<B> {..} | ||
|
||
// Required to run | ||
fn run(self) -> A {..} | ||
} | ||
``` | ||
|
||
<!-- end_slide --> | ||
|
||
# dynamic completionm | ||
|
||
- Easy to implement | ||
|
||
# Conclusions | ||
|
||
- High level overview of your app/API | ||
- Composing with CT reduces number of combinations from N^2 to N | ||
- Users don't have to know about it :) | ||
|
||
# See also | ||
|
||
- https://rustmagazine.org/issue-2/applicative-parsing/ | ||
- https://en.wikipedia.org/wiki/Category_theory | ||
- https://crates.io/crates/bpaf | ||
- https://github.com/pacak | ||
- @manpacket@functional.cafe |
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,6 @@ | ||
[package] | ||
name = "http-for-lunch" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
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,48 @@ | ||
# HTTP for Lunch | ||
|
||
This is an HTTP server which was built during the [September Rust for Lunch meetup](https://lunch.rs/meetups/2024-09-17/). | ||
|
||
The code has been left exactly as it was at the end of the meet-up, `dbg!` statements and all! | ||
|
||
## Building & running | ||
|
||
Normal `cargo` behaviour: | ||
|
||
```sh | ||
cargo run | ||
``` | ||
|
||
## Testing | ||
|
||
We ran the following requests against the server. | ||
|
||
Happy path: | ||
|
||
```sh | ||
$ curl -D - http://127.0.0.1:8080/hello | ||
HTTP/1.1 200 Rust for Lunch | ||
Content-Length: 13 | ||
|
||
Hello, World! | ||
``` | ||
|
||
Method not allowed: | ||
|
||
```sh | ||
$ curl -X POST -D - http://127.0.0.1:8080/hello | ||
HTTP/1.1 405 Method Not Allowed | ||
``` | ||
|
||
HTTP version not supported: | ||
|
||
```sh | ||
$ curl --http1.0 -D - http://127.0.0.1:8080/hello | ||
HTTP/1.1 505 HTTP Version not supported | ||
``` | ||
|
||
Not found: | ||
|
||
```sh | ||
$ curl -D - http://127.0.0.1:8080/bye | ||
HTTP/1.1 404 Not Found | ||
``` |
Oops, something went wrong.