Search code examples
chaskellfunctional-programmingpurely-functional

Unexpected Results with Functional Programming in C


While experimenting functional style in C programming, I tried to translate the following Haskell code to C.

f (0, 0, 0, 1) = 0
f (0, 0, 1, 0) = f (0, 0, 0, 1) + 1
f (0, 1, 0, 0) = f (0, 0, 1, 1) + 1
f (1, 0, 0, 0) = f (0, 1, 1, 1) + 1
f (a, b, c, d) = (p + q + r + s) / (a + b + c + d)
    where
    p
        | a > 0 = a * f (a - 1, b + 1, c + 1, d + 1)
        | otherwise = 0
    q
        | b > 0 = b * f (a, b - 1, c + 1, d + 1)
        | otherwise = 0
    r
        | c > 0 = c * f (a, b, c - 1, d + 1)
        | otherwise = 0
    s
        | d > 0 = d * f (a, b, c, d - 1)
        | otherwise = 0

main = print (f (1, 1, 1, 1))

to

#include <stdio.h>
#include <stdlib.h>

#define int const int
#define double const double

double f(int a, int b, int c, int d)
{
    if (a == 0 && b == 0 && c == 0 && d == 1)
    {
        return 0.0;
    }
    else if (a == 0 && b == 0 && c == 1 && d == 0)
    {
        return f(0, 0, 0, 1) + 1.0;
    }
    else if (a == 0 && b == 1 && c == 0 && d == 0)
    {
        return f(0, 0, 1, 1) + 1.0;
    }
    else if (a == 1 && b == 0 && c == 0 && d == 0)
    {
        return f(0, 1, 1, 1) + 1.0;
    }
    else
    {
        int p = a > 0 ? a * f(a - 1, b + 1, c + 1, d + 1) : 0;
        int q = b > 0 ? b * f(a, b - 1, c + 1, d + 1) : 0;
        int r = c > 0 ? c * f(a, b, c - 1, d + 1) : 0;
        int s = d > 0 ? d * f(a, b, c, d - 1) : 0;
        return (double)(p + q + r + s) / (double)(a + b + c + d);
    }
}

int main(void)
{
    printf("%f\n", f(1, 1, 1, 1));
    return EXIT_SUCCESS;
}

I expected the exact same behaviour, but the C program always output 0.0. With f(0, 0, 1, 1) they both output 0.5, but whenever the number gets a litter bigger, the C version simply doesn't work. What is going wrong?


Solution

  • int p = a > 0 ? a * f(a - 1, b + 1, c + 1, d + 1) : 0;
    int q = b > 0 ? b * f(a, b - 1, c + 1, d + 1) : 0;
    int r = c > 0 ? c * f(a, b, c - 1, d + 1) : 0;
    int s = d > 0 ? d * f(a, b, c, d - 1) : 0;
    

    Here the results of the recursive calls to f are truncated to an integer when they are stored in the int variables. So, for example, if a is 1 and f(a-1, b+1, c+1, c+1) is 0.5, p will be 0 instead of 0.5 because you can't store 0.5 in an int.

    In the Haskell code all variables are doubles (or rather fractionals), so you should do the same in your C version and declare all variables and parameters as double.