
Functional Language Features: Iterators and Closures - s_c_r
https://doc.rust-lang.org/book/ch13-00-functional-features.html
======
rectang
> _Programming in a functional style often includes using functions as values
> by passing them in arguments, returning them from other functions, assigning
> them to variables for later execution, and so forth._

> ...

> _Other Rust features, such as pattern matching and enums, which we’ve
> covered in other chapters, are influenced by the functional style as well._

What is it about pattern matching and enums that associates them with
functional programming? Because going by the description of functional
programming above, I don't see how they fit in. Is it just that pattern
matching and enums were first popularized by certain functional languages?

~~~
nicoburns
> Is it just that pattern matching and enums were first popularized by certain
> functional languages?

Not only were Sum Types first popularised by functional languages, most
imperative/OO languages still don't have them (although I'm not quite sure why
not). E.g. none of Java/C#/C++ have them. Neither do
Python/Ruby/JavaScript/PHP (although the need is somewhat reduced in dynamic
languages)

~~~
andrewg
C++17 does - it's called std::variant.

    
    
      std::variant<int, bool, double> options;
      options = true;
      
      bool value = std::get<bool>(options);
      bool has_bool = std::holds_alternative<bool>(options);
      
      // or test which alternative is held
      if (auto i = std::get_if<int>(&options)) {
        // do something with int
      } else if (auto b = std::get_if<bool>(&options)) {
        // do something with bool
      } else {
        // do something with double
      }

~~~
nicoburns
That's not a language feature though, right? It's just a struct containing a
union and a discriminant. That means:

\- No pattern matching means your stuck with the awkward if-elseif-else

\- It doesn't check that you've accounted for every possible variant.

\- You can only hold one variant of each type: you can't have two variants
that both contain a string.

\- The specific instance isn't it's own type, so you can't implement methods
on it.

~~~
etalian
A language that I am working on has those things "built-in" (it still
generates compilable C++ in the backend). I did recently add pattern matching
(and not just on variants) where the above would be equivalent to:

    
    
      $v:|[:int, :bool, :double] = 5;
    
      $vi: = v.[:int];
      $holds_int: = v.?[:int];
    
      switch v {
        .[:int]$i { /std cout << "got int:" << i };
        .[:bool] { /std cout << "got bool" };      
        .[:double]$d { /std cout << "got double: " << d };
      };
    

If a type repeats in the same variant, you would match by index to tell them
apart:

    
    
      $v:|[:int, :int]<(.[0] = 5);
    
      switch v {
        .[0]$i0 { /std cout << "got first int:" << i0 };
        .[1]$i1 { /std cout << "got second int: " << i1 };
      };
    

(I have some ideas to allow named labels instead of numerical indices but that
is not yet implemented)

It is, in spirit, an implementation of the inspect proposal [1], but with a
(subjectively) much simpler and more powerful syntax (the grammar of the
entire language is fully LALR(1) without ambiguities).

[1] [http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2019/p137...](http://www.open-
std.org/jtc1/sc22/wg21/docs/papers/2019/p1371r1.pdf)

------
avodonosov
Why do people post chapters from manuals to HN?

~~~
reificator
To start a discussion about that topic while bringing users who are unfamiliar
up to speed quickly?

~~~
avodonosov
Maybe. Of course, everyone can submit whatever they want. To me it looks
strange people upvote such links.

------
neuroticfish
How are iterators functional language features? They're not unique to
functional languages and they don't require function composition to implement.
They're present in most popular imperative languages.

~~~
rectang
Even if it's not the only way to implement iterators, using closures which
maintain state and yield values one after another seems to be a very popular
way to do it.

In that case you're passing around a function, which matches how this chapter
characterizes "functional programming".

------
_hardwaregeek
I've tried to use iterators and closures in my code, but it's not as easy with
error handling and lifetimes. Like I could figure out the magic incantation
that lets me map over an iterator with a function that returns a result. Or I
could write a for loop that pushes to a Vec.

Or I could chain an ok_or_else on an Option but ugh now Rust is complaining
that I'm capturing a reference to self. Screw it, I'll rewrite it to be an if
let with a return. Part of the problem there is that we know an ok_or_else
with try! will execute the closure and return if the value is None, but Rust's
borrow check doesn't know that.

None of this is Rust's fault. It's just that it's hard to combine ergonomic
closures and borrow checking.

------
gdsdfe
as a side note : I hate this ferries thing, just write a good old comment.
what's wrong with comments?

