Falcon - gregorymorrison/euler1 GitHub Wiki

The Falcon programming language, introduced in 2003, claims to support six different paradigms - procedural, object-oriented, prototype, functional, tabular, and message oriented. It comes with an interpretive shell, and also a tool to easily bundle the runtime with your script for distribution. So, let's jump in.

I found procedural programming in Falcon immediately intuitive. It took me maybe five minutes to churn out this version of Euler1 on my first time looking at the language. It looks to have borrowed from Python quite heavily:

#!/usr/bin/falcon
// Euler1 in Falcon

function Euler1(n)
    retval = 0

    for i in [1 : n]
        if i%3 == 0 or i%5 == 0
            retval += i
        end
    end    

    return retval
end

printl( Euler1(1000) )

Falcon has a full complement of functional constructs. It has versions of Map, Filter, Reduce, Lambda. There's actually a lot that's interesting here. Interestingly, I could not get map() to work here, though I found its list comprehensions a suitable replacement:

myMap = {x => x}
myFilter = {x => x%3==0 or x%5==0}
mySum = {x,y => x+y}

function Euler1(n)
    mapped = [].comp( [1:n], myMap )
    filtered = filter( myFilter, mapped )
    return reduce( mySum, filtered )
end

> Euler1(1000)

Here's an OOP version. Falcon has a rich OO implementation including multiple inheritance, static methods, and some odd concept called states, which allow you to dynamically choose a method from a collection based on the instance's current state. Oddly, constructor arguments are defined in the class, which seems to be a rather inflexible design. Falcon classes do have a init method which is not quite a constructor - parameter binding is actually done first:

class Euler1(size)
    size = size
    result = nil
    init
        // do setup operations here
    end
    function solve()
        self.result = 0
        for i in [1 : self.size]
            if i%3 == 0 or i%5 == 0
                self.result += i
            end
        end
    end
end

euler1 = Euler1(1000)
euler1.solve()
> euler1.result

Here's a Prototype example. In this paradigm, objects are just dictionaries, modifiable at runtime. In this example, I create an object with a couple properties, then for illustration I add a new method at runtime:

euler1 = bless([
    "size" => 0,
    "result" => 0
])

euler1.size = 1000

euler1["solve"] = function ()
    self.result = 0
    for i in [1 : self.size]
        if i%3 == 0 or i%5 == 0
            self.result += i
        end
    end
end

euler1.solve()
> euler1.result

Falcon has support for message passing. The subscribe() method lets objects register a message listener, and broadcast() is used to publish a message. Messages can be any type of object, and are marshaled automatically for you. Messages in Falcon are synchronous, though there is an async variant. Here is an admittedly contrived effort, with an object to marshal and a class to subscribe, and a callback function for illustration:

class Request (size)
    value = size
    callback = {=> nil}
end

class Euler1()
    result = nil

    init
        subscribe( "process", self.subMe )
    end

    function solve(size)
        self.result = 0
        for i in [1 : size]
            if i%3 == 0 or i%5 == 0
                self.result += i
            end
        end
    end

    function subMe(request)
        self.solve(request.value)
        request.callback = self.callMe
    end

    function callMe()
        > @"$self.result"
    end
end

euler1 = Euler1()

request = Request(1000)
broadcast( "process", request )

request.callback()

Falcon also touts tabular programming, which presents a table-centric way to store and interact with your data and business rules. The Table class allows you to update cells, iterate through rows, access cells by index or name, and stores heterogeneous content. In the following slightly contrived example, I've defined a formula table, which has columns for a string, a function object, a parameter, and a return value. I add two functions, euler1() and foo(), and then have some minor interaction with the table and a row:

function euler1()
    result = 0
    for i in [1 : self.size]
        if i%3 == 0 or i%5 == 0
            self.result += i
        end
    end
    return result
end

function foo()
   self.result = self.size * 2
end

funcs = Table (
    .['name', 'func', 'size', 'result'],
    .['euler1', euler1, 0, 0],
    .['foo', foo, 0, 0] )

row = funcs.find('name', 'euler1')
row.size = 1000
row.func()

> row.result

Overall, I've been finding Falcon a fun language, with lots of new-to-me concepts that make it worth my exploration. I felt that both its  syntax and compiler messages were reasonably intuitive enough to get out of my way and let me just write, even with little experience with the language. I'm not sure what kind of support it enjoys in the industry, but I look forward to working with it more in the future.

Falcon seems to come with only one executable that serves as both compiler and runtime. When you run your code, Falcon will compile it on the fly for you if you haven't earlier. Compilation and execution time feel very fast. To run, simply call falcon, passing it your program as an argument:

$ falcon euler1.fal
233168