Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function Overhead in Functional Languages like Haskell or in Hybrids like Scala [closed]

Coming from imperative languages like Python, Javascript and Java, I was very often reading about function overhead and why to avoid map from a performance perspective. Obviously these are no functional languages and foreign concepts usually tend to be less optimised and less idiomatic. I understand that calling functions is pushing values from the registers back to the stack which is expensive.

So with the recent buzz about FP concept and languages I'm really wondering how does Haskell solve this Problem? Is it just that the compilers are inlining a whole lot? In addition to that how do FP-Languages (Clojure/ Scala) on the JVM solve this Problem? Not even having a decent Tail-Call optimisation tells quite a bit about JVMs capabilities in terms of optimising FP Code.

Thank you!

like image 472
AlessandroEmm Avatar asked Apr 24 '13 19:04

AlessandroEmm


People also ask

Is Haskell a functional language?

Haskell (/ˈhæskəl/) is a general-purpose, statically-typed, purely functional programming language with type inference and lazy evaluation.

Is Scala a functional programming language?

Scala is also a functional language in the sense that every function is a value. Scala provides a lightweight syntax for defining anonymous functions, it supports higher-order functions, it allows functions to be nested, and it supports currying.

Does Scala support functional programming?

Scala lets you write code in an object-oriented programming (OOP) style, a functional programming (FP) style, and even in a hybrid style, using both approaches in combination.

What is strict functional programming in Haskell?

In a strict (call-by-value) language this will specify that arguments are evaluated before applying a function whereas in a non-strict (call-by-name) language arguments are passed unevaluated. Haskell uses call-by-name evaluation, or lazy-evaluation to evaluate expressions.


1 Answers

I can't provide a comprehensive answer for Haskell, but for Scala the answer is pretty simple: it performs transformations on the bytecode so that, for example, a (simple) tail call is implemented as a loop with variables instead. This is inherently what any language has to do to achieve good performance since computers are mutable (RAM, not WORM!).

Turning a method into something that can be passed around involves creating an object, but object creation is cheap on the JVM, and both the JVM and Scala have or will have tricks to avoid creating that object at all unless it's really necessary.

Then there's the issue of re-use of memory vs. use of new memory. That one is hard to get around entirely, but the JVM is very good at rapidly reclaiming memory, so you pay a relatively modest penalty for e.g. recreating your list each time instead of mutating the values in it. (If no references to the old list remain, you could just mutate the values and call it a new list--I don't know whether GHC plays tricks like this.) The worst situation is when you need a local update, where you can have log(n) work instead of constant-time work in some cases.

When you add all of these things together, the (single-threaded) performance penalty is often modest or negligible.

like image 91
Rex Kerr Avatar answered Oct 12 '22 01:10

Rex Kerr