The following Haskell code for multiplying an Int
by 2, when compiled with GHC 8.10.7 via ghc --make main.hs -O3
, generates a binary of 3.3M
main :: IO ()
main = do
str <- getLine
let n = read str :: Int
print $ n*2
return ()
whereas the following C++ code, compiled with GCC 11.2.0 via g++ -std=c++20 main.cpp -O3
, generates a binary of only 16K:
#include <iostream>
int main() {
int n;
std::cin >> n;
std::cout << 2*n << std::endl;
}
I tried to make the two programs as similar as I could (but please, tell me if one or both of them can be further simplified):
- both read from stdin and write to stdout;
- I believe for both of them input undergoes a string-to-int conversion (after all the command line is made of strings, not numbers), despite the conversion is explicit in Haskell and "hidden" in C++;
- both use a relatively simple data type:
int
looked like a good choice in C++, and in Haskell I made a choice which to me looks similar (Integer
would have probably been unfair).
Now I have to admit that I know very little about what actually a compiler does, so I can't be sure that the two programs above are as thin as they can be, but still, ... 200 times bigger executable for Haskell?
I've also compiled on Compiler Explorer both the C++ version and the Haskell, and I see that the assembly is ~50 lines for the former, whereas it is 260 lines for the latter.