As Rust gets fleshed out more and more, my interest in it begins to pique. I love the fact that it supports algebraic data types and in particular matching of those, but are there any thoughts made on other functional idioms?
E.g. is there a collection of the standard filter/map/reduce functions in the standard library, and more important, can you chain/compose them in a syntactical pleasing manner [1]?
Since there are already elegant means for ADTs to be used, how about monads, in particular some syntactic sugar for them?
[1] Haskell got (.) and (>>>), C# extension methods and optionally LINQ, D has unified function call syntax.
not really an object-oriented language, although it has some object-oriented characteristics. Rust is not a functional language […] It's probably best to reserve judgement about what sort of language Rust is, and see what you think once you've become comfortable with the language.
Under this definition, then, Rust is object-oriented: structs and enums have data and impl blocks provide methods on structs and enums. Even though structs and enums with methods aren't called objects, they provide the same functionality, under the Gang of Four's definition of objects.
In general, Rust does strict/eager evaluations. We can utilize higher-order functions, closures, and memoization techniques to do lazy evaluations. Take this example where Rust eagerly evaluates everything.
Although Golang supports functional programming, it wasn't designed for this purpose, as evidenced by the lack of functions like Map, Filter, and Reduce. Functional programming improves the readability of your code because functions are pure and, therefore, easy to understand.
Rust doesn't have HKT's, but its iterators do support coding in a functional style with higher order functions (HOF) like map
, filter
, fold
etc., with convenient chaining.
The details differ compared to functional languages- those are usually garbage collected, whereas Rust programs deal with memory management in a deterministic manner, similar to C++ RAII - as part of the program's flow.
To allow efficient chaining, the individual HOF's return composable lazy expression templates, and you can turn the final result into data (allocating and evaluating in one step) by finishing with .to_owned_vec()
or .collect()
or whatever.
In some situations this isn't necessary, the expression-template returned is an iterator itself and that might be sufficient. For example, you can iterate over that with a for
loop, or pass it as an argument to a generic function.
See:
http://static.rust-lang.org/doc/master/std/iter/index.html
http://static.rust-lang.org/doc/master/std/iter/trait.Iterator.html
Similar patterns are possible in both C++11 (with additional libraries) and Rust. Rust's generics aren't quite as powerful as C++ templates, but immutability by default, expression-oriented syntax, polymorphic lambdas, and two-way type inference give it a feel slightly closer to a functional language.
Regarding 'extension methods' and uniform call syntax, Rust allows a similar 'open-world' way of organizing code. You can add impl
s with more methods to any type anywhere within a library or program, or extend existing types from other libraries by implementing your own trait's methods on them.
This makes it easier to use the chainable method calling style than in C++ (i.e. less need to modify or derive types).
Bear in mind a lot of Haskell's idioms are to do with purity (e.g. the IO monad, lenses..), and Rust is multi-paradigm, not pure-functional. You can have a pure function for the benefits of referential transparency at the program level, and yet its implementation is simplified by mutable local variables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With