My first real programming experience was with Haskell. For my ad-hoc needs I required a tool that was easy to learn, quick to code and simple to maintain and I can say it did the job nicely.
However, at one point the scale of my tasks became much bigger and I thought that C might suit them better and it did. Maybe I was not skilled enough in terms of [any] programming, but I was not able to make Haskell as speed-efficient as C, even though I heard that proper Haskell is capable of similar performance.
Recently, I thought I would try some Haskell once more, and while it's still great for generic simple (in terms of computation) tasks, it doesn't seem to be able to match C's speed with problems like Collatz conjecture. I have read:
Speed comparison with Project Euler: C vs Python vs Erlang vs Haskell
GHC Optimization: Collatz conjecture
collatz-list implementation using haskell
But from what I see, simple optimization methods, including:
- choosing "tighter" types, like Int64 instead of Integer
- turning GHC optimizations on
- using simple optimization techniques like avoiding unneccessary computation or simpler functions
still don't make Haskell code even close to almost identical (in terms of methodology) C code for really big numbers. The only thing that seems to make its performance comparable to C's [for big-scale problems] is using optimization methods that make the code a long, horrendous monadic hell, which goes against the principles that Haskell (and I) value so much.
Here's the C version:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int32_t col(int64_t n);
int main(int argc, char **argv)
{
int64_t n = atoi(argv[1]), i;
int32_t s, max;
for(i = 2, max = 0; i <= n; ++i)
{
s = col(i);
if(s > max) max = s;
}
printf("%d\n", max);
return 0;
}
int32_t col(int64_t n)
{
int32_t s;
for(s = 0; ; ++s)
{
if(n == 1) break;
n = n % 2 ? 3 * n + 1 : n / 2;
}
return s;
}
and the Haskell version:
module Main where
import System.Environment (getArgs)
import Data.Int (Int32, Int64)
main :: IO ()
main = do
arg <- getArgs
print $ maxCol 0 (read (head arg) :: Int64)
col :: Int64 -> Int32
col x = col' x 0
col' :: Int64 -> Int32 -> Int32
col' 1 n = n
col' x n
| rem x 2 == 0 = col' (quot x 2) (n + 1)
| otherwise = col' (3 * x + 1) (n + 1)
maxCol :: Int32 -> Int64 -> Int32
maxCol maxS 2 = maxS
maxCol maxS n
| s > maxS = maxCol s (n - 1)
| otherwise = maxCol maxS (n - 1)
where s = col n
TL;DR: Is Haskell code quick to write and simple to maintain only for computationally simple tasks and loses this characteristic when performance is crucial?