_answ
Joined 5 years ago
Joined 5 years ago
pub fn read<P>(path: P) -> io::Result<Vec<u8>>
where
P: AsRef<Path>,
{
fn inner(path: &Path) -> io::Result<Vec<u8>> {
let mut bytes = Vec::new();
let mut file = File::open(path)?;
file.read_to_end(&mut bytes)?;
Ok(bytes)
}
inner(path.as_ref())
}
Plus, your example does not have the same semantics as the Rust code. You omitted generics entirely, so it would be ambiguous if you want monomorphization or dynamic dispatch. Your `bytes` and `file` variables aren't declared mutable. The `try` operator is suddenly a statement, which precludes things like `foo()?.bar()?.baz()?` (somewhat normal with `Option`/`Error`). And you weirdly turned a perfectly clear `&mut` into a cryptic `&!`.Please don't assume that the syntax of Rust has been given no thought.
"Show, don't tell" is good advice for creative writing, which this website isn't. As a potential customer, it shouldn't be my job to cut through the marketing fluff to figure out if a product is something that is relevant to me.
This buzzword-driven style of writing, which has infected many a software project in recent years, is a pure triumph of form over function. Maybe it is necessary to appeal to the CTO types of the industry, but as a simple developer I do find it confusing and frankly repulsive.
My one gripe about the new website (and it's something I notice many projects stumble at) is that the written copy fails to explain what the product actually is. "A better way to build products", "the new standard for software development", "a tool to remove barriers" -- this tells me nothing, unlike a simple "it's an issue tracker bro" would.
A monad is a specific variant of a higher kinded type whose primary property lies in the fact that its value can be "evolved" via a specific function application (usually known as the "bind" operation). This sounds confusing but it's really a simple concept: if you take a higher kinded type, you can think about the values within it as the data and the type itself as metadata or a context of some sort. For example, an int is a piece of data, but a `Maybe int` is the same data with the added context of it being possibly absent.
A monad is not the only higher kinded type. Probably the most familiar HKT to working programmers (even if they don't know it) is the functor, which is a type that can be mapped over (in the sense of map-filter-reduce). If you have a `Foo<A>`, you can apply a function to turn it into a `Foo<B>`. However, a limitation of the functor is that you can only affect the data at the individual item level, not the context as a whole, so if you put a list of five values in, you'll get a list of five values back.
If we want to affect the context as well, we instead need a type like the monad, where we can "bind" a function that takes the inner value and returns a whole new wrapper based on it.
Why is this useful? Well, it can express a lot of different things very neatly - for example, fallible computation. Let's say you have two functions that both return a Maybe monad. In a language with nulls, you'd likely have to do something like `a = foo(); if (a is null) return; b = bar(); if (b is null) return`, which is tedious and error prone. Monads lend themselves to composing such chains extremely well, so you can simply do `foo().and_then(_ => bar())` and in the end have a value that combines the result (success or failure) of both of those functions.
Null values = chains of null checks = monads! Futures = chains of callbacks = monads! Mutable state = chains of writes = monads! Sequential execution = chains of statements = monads! And so on and so forth. You can get pretty crazy with it, not that I would recommend it.
Monads seem complicated and scary because most mainstream programming languages don't have the necessary abstractions to talk about higher kinded types as its own thing, but in reality most programmers are using monads daily without even realizing.