Nickle - gregorymorrison/euler1 GitHub Wiki

Nickle, introduced in 2001, is an evolution of the Linux calculator utility, bc. As such, it is a general-purpose language designed for numeric processing - a desk calculator on steroids. It includes just enough functionality to get math done - namespaces, arrays, file I/O, threads, etc; while dispensing with unnecessary baggage - regular expressions, OOP, GUIs, etc. This is straight C-style procedural territory, folks. Its basic use case is as an interactive session, with REPL-like functionality such as history and a debugger.

Here's a variant of Euler1 in Nickle. There's nothing unfamiliar here - it's straight procedural C/JavaScript-style code, complete with C's string formatting. It took me maybe 10 minutes to write this, my first attempt with Nickle:

/* Euler1 in Nickle */

int function Euler(size) {
    int retval = 0;
    for (int i = 1; i < size; i++) {
        if (i % 3 == 0 || i % 5 == 0) { retval += i; }
    }
    return (retval);
}

printf("%i\n", Euler(1000));
quit;

Here's a functional version that uses tail recursion with an accumulator. One of the main points here is that the function euler() is deterministic - it will always return the same output for a given input. This is accomplished in part by the absence of any variable manipulation - there are instead only functions which return values. The other main point is that this recursion uses tail call optimization - it's written in such a way that an intelligent compiler can optimize its stack usage to be O(n) instead of O(n!). In English, this means that your program will probably not crash even for hugely recursive calls.

/* Euler1 in Nickle */

int function euler(n, acc) {
    if (n == 1) {
        return acc;
    } else if (n % 3 == 0 || n % 5 == 0) {
        return euler(n-1, acc+n);
    } else {
        return euler(n-1, acc);
    }
}

int function Euler1(size) { return euler(size,0); }

printf("%i\n", Euler1(999));
quit;

Here’s another version using a Quicksort-based algorithm. Here we recursively break the list up in half and then reassemble it. Instead of sorting each half, though, we’ll filter the pivot value, converting it to 0 if it’s not divisible. Here, euler1() returns euler1() calculated on the half of the list before the pivot element, euler1() calculated on the half of the list after the pivot element, and the pivot element or 0, all added together. Nickle does have arrays, but it doesn't seem to have array operations such as generating an array or slicing them, so I've rolled my own:

/* Euler1 in Nickle */

/* generates a list of integers from 1 to size */
int[] function range(size) {
    int[size] retval = {};

    for (int i = 0; i < size; i++) {
        retval[i] = i+1;
    }

    return retval;
}

/* returns an array slice of ints from start to end (not inclusive) */
int[] function slice(ints, start, end) {
    int[end-start] retval = {};

    for (int i = start; i < end; i++) {
        retval[i-start] = ints[i];
    }

    return retval;
}

int function euler1(ints) {
    if (dim(ints) == 0) {
        return 0;
    }

    int len = dim(ints);
    int pivot = ceil( len/2 );
    int pre = euler1( slice(ints, 0, pivot-1) );
    int post = euler1( slice(ints, pivot, len) );
    int i = 0;
    if (ints[pivot-1] % 3 == 0 || ints[pivot-1] % 5 == 0) { 
        i = ints[pivot-1];
    }

    return pre + i + post;
}

printf("%i\n", euler1( range(999) ));
quit;

Here’s one more – an elegant algorithm based on an observation by little Carl Friedrich Gauss. It operates in O(1) constant time. Don’t sweat it if this seems inscrutable; click the blog link above for an explanation.

/* Euler1 in Nickle */

int function mySum(n, size) {
    return n * (floor(size/n)**2 + floor(size/n)) / 2;
}

int function Euler1(size) {
    return (mySum(3,size) + mySum(5,size) - mySum(15,size));
}

printf("%i\n", Euler1(999));
quit;

To execute, simply yum-install nickle, then execute your code by passing it in to the runtime as an argument:

$ nickle euler1.n
233168
$