Reputation: 39340
I am trying to write a riot tag in Fsharp but am unable to do so without changing riot.
In JavaScript I should provide a function like:
function(opts) {
this.on("update",function(opts){
this.opts = opts || this.opts;
});
}
riot will then call this function using Function.prototype.call:
if (impl.fn) { impl.fn.call(this, opts); }
In F# I tried the following:
[<Emit("this")>]
let isThis (x: 'a) : obj = jsNative
let bind fn =
fun o ->
fn (isThis 1) o
[<Emit("$0 === undefined")>]
let isUndefined (x: 'a) : bool = jsNative
bind
(
fun me opts ->
me?on(
"update"
,(
fun opts ->
if not (isUndefined opts) then
me?opts <- opts
()
)
)
)
However; the bind function is transpiled to:
export function bind(fn, o) {
return fn(this)(o);
}
Not currying when I would like it to curry, the output I was looking for is:
export function bind(fn) {
return function(o){
return fn(this)(o);
}
}
The only way I can get this to work is to change riot.js to:
if (impl.fn) { impl.fn(this)(opts); }
And provide my function in F# in the following way:
fun me opts ->
me?on(
"update"
,(
fun opts ->
if not (isUndefined opts) then
me?opts <- opts
()
)
)
Changing 3rd party libraries to satisfy transpiler generated code is not ideal. Is there a way for the transpiler to generate the output I'm looking for?
[update]
A better way to do this that doesn't require changing 3rd party code is to provide the bind function as 3rd party JavaScript:
Then import it and use bind in your template code file:
let JSI =
bind<(obj -> obj -> unit) -> obj>
"../../../js/3rd/JSI.js"
bind
(
fun me opts ->
me?on(
"update"
,(
fun opts ->
if not (isUndefined opts) then
me?opts <- opts
()
)
)
)
Upvotes: 1
Views: 108
Reputation: 37131
You are hitting up against Fable's automatic uncurrying. What you need to do is replace the F# functions with System.Func
delegates to prevent Fable from uncurrying.
I was able to get pretty close with this:
[<Emit("this")>]
let jsThis : obj = jsNative
let bind (fn : Func<obj, (obj -> obj)>) =
Func<_, _> (fun o -> fn.Invoke(jsThis) o)
The generated JavaScript:
export function bind(fn) {
return (o) => fn(this)(o);
}
Upvotes: 2