Roy — small functional language that compiles to JavaScript
roy.brianmckenna.org
roy.brianmckenna.org
Especially when that language has unrestricted side effects and the example code using the monad syntax uses those side effects, completely obviating the need for, and in fact rendering useless, monads as used in the example.
This is cargo cult programming at its worst. Including monad sugar because it's the thing to do, without even understanding what monads are or why they're useful. This is quite clear from the "tracing monad" example code. This "tracing monad" is like the Writer monad, stripped of all utility and sense.
What drove you to unleash this horror on the programming masses, Moggi? Why have you cursed us so?
I didn't add monadic sugar just to be part of the "cargo cult". I added it because I'm eventually going to use it to implement an automatic continuation-passing transform. I've done a similar thing before with ClojureScript's macros:
http://lambda-the-ultimate.org/node/4117
http://ocaml.janestreet.com/?q=node/100
http://en.wikibooks.org/wiki/F_Sharp_Programming/Async_Workf...
This is something that JavaScript desperately needs.
Macros aren't so nice for this stuff in non-homoiconic languages.
I think that finding ways to notate asynchronous code cleanly is a pretty awesome goal, and I hope you find success in your project.
However, if you'll take a look at the example monad code, the bind and return methods themselves use side effects. I think that speaks for itself.
My issue is with the use of monads in particular, and I think my comment pretty well communicates that it's solely about that. I don't think it conveys a false impression about Roy as a whole at all.
Your statement that my comment "can at best be seen as attention-seeking behavior and at worst as an underhanded FUD tactic to turn people off the project" is just absolutely ridiculous. I have nothing against the project Roy, and I wish it nothing but success. Why would I possibly have any motivation to use underhanded FUD tactics to turn people off the project? And I don't even know what to say to your accusation of attention-seeking behavior. In what world is initiating a productive discussion about an important issue, and not in a self-promoting way at all, "attention-seeking behavior"? Get off your high horse.
A toy example is not an important issue. As for initiating productive discussions, I will let your comments speak for themselves
1. This is cargo cult programming at its worst
2. What drove you to unleash this horror on the programming masses, Moggi?
3. Why have you cursed us so?
4. It makes me sad that having monad sugar ....
5. .... stripped of all utility and sense.
How is a discussion not productive just because it's not framed in the most formal language possible?
https://github.com/pufuwozu/roy/blob/master/test/trace_monad...
let traceMonad = {
return: fn x =
console.log "Return:" x
x
bind: fn x f =
console.log "Binding:" x
f x
}
console.log (do traceMonad
bind w = 1
let x = 2
bind y = 3
bind z = 4
return w + x + y + z
)To be a monad, return must be a left and right identity:
x >>= return = x
return x >>= f = f x
By having return do things other than wrapping the value, the monad laws are broken.Similarly, bind cannot have such effects, it would break its associativity.
data Option a =
Some a | None
let optionMonad = {
return: fn x =
Some x
bind: fn x f = match x
case (Some a) = f a
case None = None
}
let m = (do optionMonad
bind x = Some 1
let y = 2
bind z = Some 3
return x + y + z
)
match m
case (Some x) = console.log x
shows an error Error: Type error: Native is not Option 'dwkhttp://dojotoolkit.org/reference-guide/dojo/Deferred.html http://api.jquery.com/category/deferred-object/
new deferred objects can be created manually or obtained from say, an AJAX function (this is the equivalent of "return")
async operations can be chained with the deferred.then method (this is a hybrid of "fmap" and ">>=", aka "bind")
Code looks something like this:
...
(* long_running_call : unit -> string Deferred.t *)
long_running_call ()
>>= fun result ->
print_endline result
...
Running calls in parallel is easy. Say we want to run a couple of queries against a db at once, and only perform an action once both return: ...
(* Db.query : Db -> Db.Query -> Db.Result Deferred.t *)
let d1 = Db.query db query1 in
let d2 = Db.query db query2 in
d1 >>= fun r1 ->
d2 >>= fun r2 ->
...
If you have questions about getting it set up/using it, the mailing list is the place to ask: https://groups.google.com/forum/#!forum/ocaml-core Monitor.try_with : ?name : string
-> (unit -> 'a Deferred.t)
-> ('a, exn) Result.t Deferred.t
It takes two arguments. Name is used to tell you what monitor the error was caught by. The second is a function that returns some kind of Deferred.t. The whole thing returns a (deferred) Result.t (: [`Ok of 'a | `Error of exn]), letting you either do something with the results of the async call or handle the error. Usage might be something like this: (* query_or_print : Db.t -> Db.Query.t -> Db.Result.t option Deferred.t *)
let query_or_print db query =
Monitor.try_with (fun () -> Db.query db query)
>>| function
| `Ok result -> Some result
| `Error e -> print_endline (Exn.to_string e); NoneLooking at the JavaScript, though, all those anonymous functions can't be very fast.. I wonder if the compiler could try to defunctionalize the output..
return (function() {
if(b instanceof True) {
return ifTrue;
} else if(b instanceof False) {
return ifFalse;
}
})();
Can just become: if(b instanceof True) {
return ifTrue;
} else if(b instanceof False) {
return ifFalse;
}
The output of `with` is pretty gross. Definitely want to hear ideas on how to clean it up :)For instance, for this Roy generated JS:
var True = function(){};
var False = function(){};
var getBool = function(b, ifTrue, ifFalse) {
return (function() {
if(b instanceof True) {
return ifTrue;
} else if(b instanceof False) {
return ifFalse;
}
})();
}
The Closure compiler generates: var True = function() {
}, False = function() {
}, getBool = function(b, c, d) {
var a;
b instanceof True ? a = c : b instanceof False && (a = d);
return a
};I could rely on Closure for optimal performance but what I really want is optimal readability.
The example on Types is not compiling as it is. The last line should be something like:
console.log (getName {firstName: "John", lastName: "Doe"})No partial application allowed here, so what is the point? =\
let add a b = a + b
let add2 = add 2
Does not work. let fact a =
if a == 0 then
1
else
(fact (a-1)) * a
Does not support recursion like this either. The "functional" description brought my expectations too high I think.It compiles to very lean Javascript though, so that's a big plus.
let fact a =
if a == 0 then
1
else
(fact (a - 1)) * a
console.log (fact 5)
Now, it's true that the Haskell syntax does not make that much sense if there is no partial application. I think that the variadic-arguments-are-always-allowed nature of JavaScript is not very compatible with partial application though.It could be implemented by compiling Roy functions to chains of 1-arg functions, but the amount of recursion and funcalling would probably be expensive (JS is not very good at these).
A SmartEnoughCompiler® you could also see partial application points and craft a partial application right there:
let add x y = x + y
console.log (add 1 32)
let add2 = add 2
console.log (add2 5)
var add = function (x, y) { return x + y; };
console.log(add(1, 32));
var add2 = function (y) { return add(2, y); };
console.log(add2(5));
As long as the number of arguments can be understood at compile time (which it can), it's not that hard: if the number of arguments provided make the function's arity reach 0 you partially apply it (and decrease the arity of the result), otherwise you fully apply it.I'll have a go and see how well it works. Thanks!
That should be fixed.
I've really missed static typing on Javascript and Coffeescript; little typos are so hard to find! Structured typing really sounds like the way to go for putting type checking into Javascript, and I like how, just like Coffeescript, Roy tastes a lot like Javascript otherwise - avoiding all kinds of leaky abstractions you get with less JS-like languages. Plus, it has a sexy syntax.
I'd like to try this out in a real project. Is that being done already?
There are some characters that shouldn't be there in the middle of the file, thus demo is broken.
OTOH, string typing will greatly reduce your errors.