Functional Features

Monkey Forums/Monkey Programming/Functional Features

maltic(Posted 2012) [#1]
Is there any chance we will ever see anonymous functions and or closures in monkey? Personally I would love to see them, but I understand it might be a tricky feature to implement at present. Having said that, Java 8 will have support for these (it could also be done via some Scala/Java interop, I imagine), C++11 already supports them, javascript does, no idea about flash/AS (a quick google search implies that it does) but C# certainly does (XNA). So maybe a year or two down the track?

Also, it is my understanding that rudimentary support for anonymous functions can be achieved by converting them to actual functions at compile time, then just providing a reference to them when they are used. Of course this would mean adding a native type for functions (I have no idea how this would be done), or perhaps representing them as objects (though this might slow down the GC a lot on mobile devices). Similarly closures can be implemented as a big state table for your compile time created anonymous functions.

Does anyone else think this would be a cool feature, or is it just me? Maybe I've missed something and it might be much harder than I think--to clarify, I think this would be /very hard/ to implement, but definitely possible. Is there are way I can create my own compiler extension of trans to attempt to support them on say javascript as a proof of concept? I do of course worry about making 'function' a primitive type; I have no idea how to do this, but I am willing to try.

P.S. Obviously you can fake these things using objects, I am talking about native support that won't kill the GC and/or has a nice syntax.


MikeHart(Posted 2012) [#2]
Ok, I got it that you like these? But for what do you need these? Can you explain it in some pseudo code?

From what I take of wikipedia explainations is, that you want to be able to access fields/objects that are outside of the scope a current function/method. I wonder why?


Samah(Posted 2012) [#3]
Java 8's closure support is a dirty hack that generates anonymous classes. I'm quite disappointed with it actually :(


maltic(Posted 2012) [#4]
@Samah: Oh I didn't know that! That is appalling, but I guess it means I could claim these features are possible for the trans compiler in the current versions of Java by just using an anonymous class, however I still think compiling a bit of Scala and grafting it onto the Java is a better idea. I have all but given up on Java. Clojure or Scala for me on the JVM.

@MikeHart: What you have described is one small aspect of what you can do with closures. Monkey is a turing complete language (at a glance..?), and functional languages are based on lambda calculus which was proved by Alonzo Church and Alan Turing to be equivalent to turing complete. So there is nothing you can't do in Monkey now that you could do with these features. However that is also true for objects and generics. Like those lambdas would make certain things much more succinct.

Basically a lambda is a function that is defined on the fly, here is a classic example:
function map:int[](elems:int[], f:function)
    for local i:= 0 until elems.Length
        elems[i]=f(elems[i])
    next
    return elems
end
local myArray := map([1,2,3,4], fn (i) -> i+1)
' myArray contains 2, 3, 4, 5

jQuery is pretty much built on anonymous functions. Haskell is an entire language (which I personally love and use quite a lot) based on immutability, lambda functions, algebraic data types and lazy evaluation. Most languages these days support lambda functions because they can be so useful. Off the top of my head one could change the Map and List classes to take a comparator function as an argument in sort so you don have to extend the classes and write it yourself!

local sorter:function = fn (a:int, b:int) ->
    return a > b
end
local l:=new List<Int>
'add stuff to l
l.Sort(sorter)


Note: I just wrote this code on the fly and made up some syntax. It might be a bit dodgy, but you should get the idea.

More Info and proof that almost all mainstream languages support lambda functions: http://en.wikipedia.org/wiki/Anonymous_function


frank(Posted 2012) [#5]
In Javascript/Jquery you have things like:

$.get("http://google.com", function(result) {
console.log(result);
});

Which you automatically (have to) use all the time, while most people don't know that's an anonymous function (and, to some extend, don't need to know this).

But there are a lot of constructs from functional programming which benefit Monkey devs which result in cleaner, better code in general:

- map functions to a list

map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]

- each; iterate over each element

each([1, 2, 3], Print);
=> 1
=> 2
=> 3

- reduce (foldl) turns a list into 1 value

reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
=> 6

- find ; returns the first value in the list which results in true from the function

find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2

- filter all values for which the function returns true

filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]


Etc. These functions save a LOT of code when used properly and make code very readable instead of, for instance, making nested loops to try to recreate the same behavior or writing elaborate classes/methods to try to make them generic.


Shinkiro1(Posted 2012) [#6]
Recently learned javascript/jQuery in school and anonymous functions really impressed me.

The coolest thing I think is that you can do something like this:
//moveObject(x, y, onFinished)
moveObject(10, 20, function() {
	// Execute when finished moving
});

You don't have to design an extra event system and scatter your code all around.
To me it feels very natural to write this way.

But I think to implement this monkey would have to treat functions as first class citizens?


maltic(Posted 2012) [#7]
@Shinkiro1: Yes, to have anonymous functions, we need to treat them as a data type, a first class citizen. You've also highlighted another reason why they can be useful: callbacks. For example, instead of extended the App class, or the DiddyApp class (or whatever framework you are using) you could simply create an instance then pass it your update and render functions. On top of that, there are continuations, I've always found continuation passing comes in handy when you least expect it.

One could also make a component based system using functions as little packets of behaviour, then gluing together an entity using currying and function composition. The cool thing about this is you could change the definition of what a type of entity is /at runtime/ with very little overhead. It would also make for really clean reusable code! With immutable data structures you could even start doing some FRP (although I would advise against it).

eg.
local anEntity:= composeFn([renderable(theScreen), followAI(player), particleEmitter(FAIRY_DUST)])

'---update/render/everyhing loop
for local e:=eachin Entities
    e()




Samah(Posted 2012) [#8]
@maltic: On top of that, there are continuations

There's a simple coroutine/continuation implementation in Diddy if you want to use the threading module.


maltic(Posted 2012) [#9]
@Samah: I did not know that, I will have to check it out.


MikeHart(Posted 2012) [#10]
Mark said one time that we won't get pointers so how does this affect this?


maltic(Posted 2012) [#11]
@MikeHart: Not in the slightest. Pointers are an imperative concept.


ziggy(Posted 2012) [#12]
We do have them. Object instances are pointers, just give it a bit of imagination and you can do almost anything but, with a proper delegates implementation, you would need a lot less of imagination and everything would be much more straight forward but I feel a bit alone on this feature request for Monkey


maltic(Posted 2012) [#13]
Correct me if I'm wrong, but I am pretty sure objects in Monkey are handled by reference, and are not by pointer (using C/C++ nomenclature).


ziggy(Posted 2012) [#14]
You're not wrong, but a reference and a pointer are sort of the same, except that a reference is cooler as it allows languages to have a garbage collector. That was what I was meaning, but maybe it was not very well written or explained.