Squirrel - gregorymorrison/euler1 GitHub Wiki

From the official site:

Squirrel is a high level imperative, object-oriented programming language, designed to be a light-weight scripting language that fits in the size, memory bandwidth, and real-time requirements of applications like video games.

Squirrel was introduced in 2003 as a replacement for Lua, which it takes its design cues from. Likewise, it was meant to serve the same purpose - a small, embeddable scripting runtime for applications like games. It has a checklist of modern features: OOP, garbage collection, C bindings, lambdas, closures, generators, a REPL, etc. So, what does it look like? Well, this imperative version of Euler1 looks pretty much like JavaScript - C-style syntax, dynamic typing, optional semicolons, etc:

// Euler1 in Squirrel

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

print( Euler1(1000) + "\n" );

Here is an example using the canonical functional functions, map/filter/reduce. I'm not sure if squirrel can generate ranges of integers, so I rolled my own. Here, map is kinda contrived - this algorithm doesn't need anything mapped, so it just returns itself, but it is illustrative of how the operations work:

#!/usr/bin/squirrel
// Euler1 in Squirrel

// generate a list of ints
function genInts (i, acc=[]) {
    acc.append(i);
    if (i == 0) {
        return acc;
    } else {
        return genInts(i-1, acc);
    }
};

function Euler1(size) {
	local ints = genInts(size)

	local mapped = ints.map( function(val) {return val} )
	local filtered = mapped.filter( function(idx,val) {return val%3==0 || val%5==0} )
	local reduced = filtered.reduce( function(x,y) {return x+y} )

	return reduced;
}

print ( "Euler1 = " + Euler1(999) + "\n" );

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, euler() returns euler() calculated on the half of the list before the pivot element, euler() calculated on the half of the list after the pivot element, the pivot element or 0, and the accumulated result, all added together. Note the short-circuit conditional in the middle of that mess. And I couldn't find a range generation function in Squirrel, so I had to roll my own, demonstrating tail recursion:

// Euler1 in Squirrel

// calculate solution based on Quicksort problem decomposition
function euler(L) {
    if (L.len() == 0) return 0

    local pivot = L.len() / 2

    return (euler( L.slice(0,pivot) )
          + euler( L.slice(pivot+1) )
          + ( (L[pivot]%3 == 0 || L[pivot]%5 == 0)  &&  L[pivot]  ||  0 ))
}

// generate a list of ints using tail recursion
function genInts (i, acc=[]) {
    acc.append(i);
    if (i == 0) {
        return acc;
    } else {
        return genInts(i-1, acc);
    }
};

function Euler1(size) {
    return euler( genInts(size) );
}

print ( Euler1(999) + "\n" );

Here's an OOP example. As in other dynamic languages, classes are extensible at runtime; notice I added a method at runtime. Squirrel supports single inheritance, though I couldn't find evidence of interfaces. Classes also have accessible metadata, also.

// Euler1 in Squirrel

// a class with a constructor
class Euler1 {
    constructor(n) {
        size = n
    }
    size = null
    result = 0
}

// dynamically extend the class at runtime
function Euler1::solve() {
    for (local i = 0; i < size; i += 1) {
        if (i%3 == 0 || i%5 == 0)
            result += i;
    }
}

local euler = Euler1(1000)
euler.solve()
print ( euler.result + "\n" )

So, what's my opinion? Well, it didn't take that long to write these examples - maybe a few hours each. And the error messages are okay - particularly nice is the debug output including variable values as well as stack trace. But a lot of the language just felt immature. I couldn't get any of the functional elements to work after a few hours of trying. The documentation feels incomplete. The distribution is pretty bare-bones - it's meant to be embeddable, so it's Batteries Not Included. And it looks like the distribution has a REPL, but I couldn't get that to work, either, nor could I find documentation on it.

Also, I didn't find anything compelling about the language. I didn't find anything new or different about it. Maybe there is a niche for the language in the embeddable space, but I'm not seeing it.

If you want to try it, yum-install squirrel. Then, run squirrel, passing it your code as an argument:

$ sq euler1.sql
Euler1 = 233168
$