Closed dy closed 9 years ago
:add (a,b)->
a+b
:add (a,b)->
a+b
add 1, 2
Compiles to:
(function add(a, b){
return a + b;
});
add(1, 2);
Function add
remains undefined in outer scope
Which is how function scoping works in js. You want something that "upvar"s to the highest scope?
Yes, is it possible to make named function in current scope?
I'm not sure what you mean ?
let
function a =>
console.log "a ?" a?
console.log "a ?" a?
this gives true then false
Ok, I got this, thanks. I didn’t know the function a =>
notation, couldn’t find it in docs.
But what about topic proposals?
Function guards are mostly covered by implicit switch:
color: (el)->
| el instanceof Element => @set 'color', @parse window.getComputedStyle(prop)['background-color']
| el? => @set 'color', @parse prop
| otherwise => @get 'color'
Yes, but it feels a bit messy to place params matching and guards in function body. Erlang-way looks clearer: there are examples in learnsomeerlang.
could use match
color = (el) ->
match el
| (instanceof Element) => ...
| (is null) => ...
| otherwise => ...
but I don't think that's relevant when we have almost no "types"
At least it would possible to match number of arguments and value:
on: (event, cb) ->
...
on: (event, selector, cb) ->
...
on: ("hover", over, out) ->
@on "over", over
@on "out", out
on: ("drag", start, drag, stop) ->
@on "dragStart", over
@on "drag", drag
@on "dragStop", stop
We'd need to add runtime hacks in order to do that. And how do we do for dynamic names?
obj[f] = (a,b) -> ...
obj[f] = (a) -> ...
method = "do"
class A
"#method": -> ...
Ok, I see, there’s no way to make it dynamically.
Another idea for pattern matching. It looks handy to have pattern mathing for objects and lists in switch, like so:
switch params
| {format:"rgba", omitAlpha:true} => @@format.rgb.toString(@model)
| {format:"rgba"} => @@format.rgba.toString(@model)
| {format:"hex", shorten} => @@formats.hex.toString(@model, shorten)
| {target in @@components, normalize = false} => @@component[target].toString(@model, normalize)
| otherwise => @@formats.rgb.toString()
It’s more readable and concise than
switch params
| params.format is "rgba" and params.omitAlpha is true => @@params.format.rgb.toString(@model)
| params.format is "rgba" => @@params.format.rgba.toString(@model)
| params.format is "hex" and params.shorten? => @@formats.hex.toString(@model, params.shorten)
| params.target in @@components => @@component[target].toString(@model, normalize)
| otherwise => @@formats.rgb.toString(@model)
Something like
match params<[format omitAlpha shorten target]>
| 'rgba', true, _, _ => ....
| 'rgba' , _, _, _ =>
| 'hex', _, (isnt null), _ => ....
| _, _, _, (in @components) =>
| otherwise => ...
That’s really nice, thanks. Is there any docs on match and underscore?
Match is still experimental
Seems that neither list of words nor spread work with match:
a = {c:1}
match a<[b c]>
| (?), (?) => 1
| (?), _ => 2 #=>
| _, (?) => 3
| _, _ => 4
l = [1, 2, 3]
match ...l
| _ =>
What a shame.
Ah, right, we need splat.
If the function signatures match, we could get "fake" overloaded methods by just compiling the ones in the same scope down to a giant switch — which would be an optimization in an actual overloaded method:
fib = (n) when (n == 0) -> 0
fib = (n) when (n == 1) -> 1
fib = (n) -> (fib (n - 1)) + (fib (n - 2))
Would compile down to:
fib = (n) ->
| n == 0 => 0
| n == 1 => 1
| otherwise => fib(n - 1) + fib(n - 2)
This could be confusing (perhaps?), since:
head = (xs) when isArray(xs) -> xs[0]
( ... a shit load of lines afterwards, in another scope ...)
head = (xs) when isString(xs) -> xs.charAt(0)
Would compile down to:
head = (xs) ->
| isArray(xs) => xs[0]
( ... )
head = (xs) ->
| isString(xs) => xs.charAt(0)
At any rate, a supporting runtime for this would only be necessary if we allow these functions to be extended at runtime (e.g.: Clojure's multi-methods). Otherwise we can safely do pattern matching. The propsed syntax is not that nice, though.
Erlang guards only allow basic checks and some BIF (to avoid side effects). Would we take that path or not?
Yeah, Erlang function guards are fairly restrictive, most likely for performance reasons. Now that I've got some limited Erlang coding under my belt, I guess we could achieve the same sans the confusing semantics in my previous suggestion by adopting a new block of patterns:
map = match-fun
(f, xs) when isArray(xs) --> [f x for x in xs]
(f, object) when isObject(object) --> [f k, v for k, v of object]
(f, functor) when isFunctor(object) --> functor.map f
Would compile down to something like:
var map = function() {
var cases = [
curry$(function (f, xs) { ... }),
curry$(function (f, object) { ... }),
curry$(function (f, functor) { ... })
]
return function _(arg$1, arg$2) {
switch (false) {
case !(arguments.length == 2 && isArray(arg$2)):
return cases[0].apply(this, arguments)
case !(arguments.length == 2 && isObject(arg$2)):
return cases[1].apply(this, arguments)
case !(arguments.length == 2 && isFunctor(arg$2)):
return cases[2].apply(this, arguments)
default: return _.bind(this, arguments)
}
}
}()
The semantics of match-fun
basically boils down to:
when
guard may be added to a case. When such a thing happens, known bindings for the function declared in that case are substituted to the related positional parameter. If there exists a destructuring declaration for that pattern, the binding has to be resolved just before the guard is tested, such that patterns down the road don't affect the performance of the previous cases.when
clause should take any valid LiveScript expression.I'll go ahead and close this, since this would require a "sealed"-like keyword for our functions. (which we can't really do anyway)
Now it compiles to dubious:
It would be better to have named function instead:
Just suggestion.
Another idea: function clauses & guards. It would be super-useful to write clauses that way:
It complies to current syntax of guards.