Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipelining section question #2

Open
isaacabraham opened this issue May 31, 2021 · 2 comments
Open

Pipelining section question #2

isaacabraham opened this issue May 31, 2021 · 2 comments

Comments

@isaacabraham
Copy link

I'm not sure (warning: I'm not a Rust dev so might be completely wrong here) that the two examples (map.filter vs addOne |> addOne) are really equivalent.

Isn't the map. filter etc. nature of that sample more about library functions, iterators and how collections are evaluated? In F#, probably the closest would be using Seq e.g.

let answers =
    [ 1 .. 10 ]
    |> Seq.map (fun x -> x * 2)
    |> Seq.filter (fun x -> x > 5)

And indeed in the example above, no real computation happens until you "evaluate" the query using e.g. Seq.toList or some other function that executes the sequence.

So, yes, |> does eagerly evaluate, it's really just syntactic sugar for calling the last argument in a function on the LHS of the pipeline - but that doesn't preclude the kind of lazy evaluation you're referring to.

Might be completely wrong here though, so feel free to ignore this if I've misunderstood!

@Dhghomon
Copy link
Owner

That does look a lot closer, yes, since you're just setting up a non-eagerly evaluated structure that doesn't actually do anything until you try to do something with it. I think it's different on the back end since here it's making a seq whereas the Rust-ish version of the F# type might be like a filter<map<seq>>, but I guess sequences themselves are lazy so maybe the end effect is similar. In the meantime this will be good to add to the section (since Rust users will want to know about sequences for sure).

@ChayimFriedman2
Copy link
Contributor

In the same manner, this part is wrong:

This is because calling these iterator methods without collecting them or assigning them to a variable just makes a big complex type; we haven't mapped or filtered anything yet. Let's see what it looks like by getting the compiler mad:

fn main() {
    let times_two_then_even: i32 = (0..=10) // Tell the compiler it's an i32
        .map(|number| number * 2)
        .filter(|number| number % 2 == 0);
}

The compiler complains:

expected type `i32`
     found struct `Filter<Map<RangeInclusive<{integer}>, 
     [closure@src/main.rs:3:14: 3:33]>, [closure@src/main.rs:4:17: 4:41]>`
     

So all we've done is put together a type Filter<Map<RangeInclusive etc. etc. etc. And if we call .map a whole bunch of times it just keeps on putting this big struct together:

found struct `Map<Map<Map<Map<Map<Map<Map<Map<RangeInclusive<{integer}>, [closur
e@src/main.rs:3:14: 3:33]>, [closure@src/main.rs:4:14: 4:33]>, [closure@src/main
.rs:5:14: 5:33]>, [closure@src/main.rs:6:14: 6:33]>, [closure@src/main.rs:7:14: 
7:33]>, [closure@src/main.rs:8:14: 8:33]>, [closure@src/main.rs:9:14: 9:33]>, [c
losure@src/main.rs:10:14: 10:33]>`

This struct is all ready to go, and gets run once when we actually decide to do something with it (like collect it into a Vec). The pipeline operator in F#, however, gets run every time you use it: if you do something like this:

let addOne x = x + 1;

let number  = 
    addOne 9
    |> addOne
    |> addOne
    |> addOne
    |> addOne
    |> addOne
    |> addOne

It's going to call addOne every time, and same for F#'s iterator methods.

The pipe operator in F# exactly equals the calling syntax (a |> b is exactly the same as b (a), just more convenient sometimes). And same in Rust, a.b() equals b(a) (or b(&a), or b(*a), or b(&mut *a), but that is because of deref coercion). The difference between Rust and F# in this example is that Rust iterators are lazily evaluated, and F# List methods are not. Still, as mentioned bt @isaacabraham, F# has Seqs which are lazy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants