15

Recently I asked about how to put a bunch of closures with the same signature into a vector in Rust. Coming from a Haskell background, it seemed a bit complicated, with Rust closures each having their own unique types and needing a trait to represent them. In Haskell, a lambda is typed by its signature and if the signature is the same, the type is the same.

Is there a semantic difference between a Rust closure and a Haskell lambda function that makes for these differences?

  • 1
    Does Haskell monomorphize their closures? I know there's some aspects around stream fusion... – Shepmaster Feb 28 '18 at 18:52
  • @Shepmaster I am not an expert in Haskell, and only a beginner in Rust, which is why I'd like to know. –  Feb 28 '18 at 19:02
  • 3
    @Shepmaster No, Haskell closures are no more monomorphic than they need to be (with one occasionally annoying exception for top-level definitions, the monomorphism restriction, and even that can be turned off with a compiler flag). – Daniel Wagner Feb 28 '18 at 19:37

1 Answers1

12

Rust's choice of using distinct types has two performance benefits:

  • The compiler can stack allocate the data you close over (or embed it into the containing data structure)
  • Since it knows which function the closure references at compile time it can statically dispatch the call and even inline the call.

You can also choose to use Box<Fn> instead. That costs a heap allocation and results in an indirect call, but in exchange there is only one type per signature.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • 1
    FTR, Haskell lambdas can very often be inlined too. It just usually requires that the higher-order function you _pass_ the lambda to is inlined first, which can be a bit of a code bloat (but this is actually quite similar to what C++ and Rust do when instantiating templates over a lambda's type). – leftaroundabout Mar 01 '18 at 10:45