FunScript/F# is the only statically-typed compile-to-js language poised to take full advantage of the JavaScript ecosystem. F#'s type providers make consuming JavaScript possible without any code generation or foreign function interface definition. FunScript has taken the first steps to making t...
FunScript/F# is the only statically-typed compile-to-js language poised to take full advantage of the JavaScript ecosystem. F#'s type providers make consuming JavaScript possible without any code generation or foreign function interface definition. FunScript has taken the first steps to making this a reality by consuming TypeScript definitions files. However, the F# community has more ambitious plans to consume pure JavaScript files too. Seamless integration with the node package manager might also be on the horizon. Find out more at: http://funscript.info/ http://fsharp.org/ and http://zbray.com/
Size: 2.73 MB
Language: en
Added: Jan 31, 2013
Slides: 33 pages
Slide Content
FunScript
Zach Bray 2013
Me
•Energy trading systems
•C#/F#/C++
•Functional
zbray.com
@zbray
* Lots of F#
* Calculation Engine
* Not a JS expert
What is FunScript?
// F# Code -> JavaScript Code
Compiler.Compile: Expr -> string
* F# Code -> JS Code
* Quotation Expr -> String
* Quotations in F# provide a way of getting the AST from a piece of code.
What does it support?
•Most F# code
•A little mscorlib
•400+ bootstrapped tests
* Bootstrapped: FSharp.PowerPack + JInt
Primitives
•Strings
•Numbers (beware!)
•Booleans
* Ints/Bytes/etc. all converted to number.
* Loops that look infinite can turn out to be finite...
Flow
var _temp1;
if (x)
{
_temp1 = "foo";
}
else
{
_temp1 = "bar";
};
var y = _temp1;
return y;
let y =
if x then "foo"
else "bar"
y
let xs = [1; 2; 3]
match xs with
| x::xs -> x
| _ -> failwith "never"
var xs = List_CreateCons(1.000000,
List_CreateCons(2.000000,
List_CreateCons(3.000000,
List_Empty())));
if ((xs.Tag == "Cons"))
{
var _xs = List_Tail(xs);
var x = List_Head(xs);
return x;
}
else
{
throw ("never");
}
* Inline if... then... else... blocks
* Pattern matching
* While + For loops
* Caveat: Quotation Problem: “for x in xs” when xs is an array
Functions
(fun x -> x % 2 = 0)(2)
return (function (x)
{
return ((x % 2.000000).CompareTo(0.000000) == 0.000000);
})(2.000000);
let isOdd x = x % 2 <> 0
isOdd 2
var isOdd = (function (x)
{
return ((x % 2.000000).CompareTo(0.000000) != 0.000000);
});
return isOdd(2.000000);
* Let bound functions
* Anonymous lambda functions
* Note/Caveat: CompareTo rather than operators: Allows structural equality. Has negative
impact on performance. Cite: Mandelbrot test by Carsten Koenig 100x worse than JS vs.
1000x for Fay.
Records
var i_Person__ctor;
i_Person__ctor = (function (Name, Age)
{
this.Name = Name;
this.Age = Age;
});
var bob = (new i_Person__ctor("Bob", 25.000000));
type Person =
{ Name: string; Age: int }
let bob =
{ Name = "Bob"; Age = 25 }
...but also discriminated unions, classes and modules
var now = (new i_Person__ctor("Bob", 25.000000));
var _temp1;
var Age = 26.000000;
_temp1 = (new i_Person__ctor(now.Name, Age));
var soon = _temp1;
let now = { Name = "Bob"; Age = 25 }
let soon = { now with Age = 26 }
* Most of the types you can define
* Records, DUs, Classes, Modules
* Records very similar to JSON.
* Record expressions are shallow copies with some changes
* Records & DUs have structural equality.
* Caveat: Class inheritance doesn’t work (yet)
* Caveat: DU structural equality is broken on the main branch.
Operators
var xs = Seq_ToList(Range_oneStep( 10.000000, 20.000000));
let xs = [10 .. 20]
var xs = Seq_ToList(Range_customStep( 10.000000, 2.000000, 20.000000));
let xs = [10 .. 2 .. 20]
let incr x = x + 1
let x = 10
x |> incr
var incr = (function (x)
{
return (x + 1.000000);
});
var x = 10.000000;
return incr(x)
var incr = (function (x)
{
return (x + 1.000000);
});
var divBy2 = (function (x)
{
return (x / 2.000000);
});
return (function (x)
{
return incr(divBy2(x));
})(10.000000);
let incr x = x + 1.
let divBy2 x = x / 2.
(incr << divBy2) 10.
* Logic & Arithmetic too (obviously)
* But also... identity, ignore, defaultArg, reference assignment etc.
* Can also define your own.
* See the tests for a complete list.
Computation
expressions
async { return () }
|> Async.StartImmediate
return (function (arg00)
{
return Async_StartImmediate(arg00, {Tag: "None"});
})((function (builder_)
{
return builder_.Delay((function (unitVar)
{
var _temp3;
return builder_.Return(_temp3);
}));
})(Async_get_async()));
* Async workflow built in...
* Can define your own too, e.g., the maybe monad if you wanted it
* LiveScript has the concept of back calls
Data structures
•Array
•List
•Seq
•Map
•Set
•Option
Bored yet?
Boring bit over (hopefully).
We’re half way to the pub.
Why bother?
Enormous number of devices. More than .Net or Mono.
Not just for the browser.
* Desktop Apps.
* Tablet/Phone Apps.
* Servers.
Don’t we have this
already?
•FSWebTools
•WebSharper
•Pit
•JSIL
F# has a long history of compiling to JavaScript
Tomas released FSWebTools back in 2006 or 07.
Co!eeScript appeared in 2009.
But FunScript is focusing on something slightly di!erent...
Extensibility
We cannot port the whole framework.
... but we can give you the tools to chip o! the bits you need.
Movie data example
Tomas built this web app with FunScript.
No .NET the whole thing runs in JS.
* Who is familar with type providers?
* Like code gen, but without the manual step and can be lazy (which is great for stu! like
freebase)...
Mapping the Apiary.io
type provider
•Makes calls to the framework
•Not quotation friendly
•We replace (or re-route) the calls to
quotation friendly methods and types
ExpressionReplacer.createUnsafe <@ ApiaryDocument.Create @> <@ JsonProvider.JsRuntime.CreateDocument @>
ExpressionReplacer.createUnsafe <@ fun (d:ApiaryDocument) -> d.JsonValue @> <@ JsonProvider.JsRuntime.Identity @>
ExpressionReplacer.createUnsafe <@ fun (d:ApiaryDocument) -> d.Context @> <@ getContext @>
Compiler.Compile(<@ page () @>, components=FunScript.Data.Components.DataProviders)
* We cannot use the provider out of the box...
* But because the compiler is EXTENSIBLE we can tell it how to convert those calls.
* It [the compiler] will find all call sites and change them.
* Then we can use the provider in our JavaScript output
* Any questions on that?
* OK so...
* That’s one feature that existing implementations don’t have.
* What else?
What about these?
See: http://altjs.org/
Elm
* Many languages target JavaScript now.
* It has become a kind of IL.
* Some are quite good. I recommend LiveScript if you don’t mind something dynamic.
Dynamically typed
•
Good at interop
•
But if its too close to
JavaScript...
* Can reuse existing libraries
* Can consume JS data
* But...
* Inconsistent operations (annoying on forms)
* Dodgy for ... in ... loops, although fixed in most compile to JS languages
* Dodgy function scope. Yuck!
* Counter-intuitive “Falsey” values
* Auto semi-colon insertion
Statically typed:
FFI sucks
* Foreign function interface
* Have to map every function you want to use
* Tedious and error prone - may as well go dynamic
* This is Fay. But same in Roy, js_of_ocaml, etc.
* Can do this in FunScript too.
The Lonely Island
* If you have to use FFI you are a lonely island
* Cannot easily access any of the existing JavaScript infrastructure
Bypass FFI with type
providers
* Uses similar techniques to those I described in the Movie example
* The TypeScript library creates a bunch of types and tells the compiler how to turn them into
JavaScript.
* F# is the only language that supports this workflow at the moment!
Just the beginning
•TypeScript only has mappings for 10s of
JavaScript libraries.
•Google Closure annotations
•JavaScript type inferrer
* Google closure might provide many more mappings
* JavaScript type inferrer would probably be very hard to build but it would be awesome
- EDIT: Colin Bull has already made a little progress towards this: https://github.com/
colinbull/IronJS/commit/612b799351a37d720920d4c68797787d2b72aaca
- EDIT: We could even have a type provider to the node package manager (NPM) then we
wouldn’t even need to mess around with files. For example:
type npmProvider = NodePacakgeManager()
let npm = npmProvider.GetContext()
let express = npm.express.v3_1_2
let connect = npm.connect.v2_7_2
...
GitHub numbers
•
JavaScript: #1
•
FSharp: #43
Sources:
www.github.com/languages/
www.r-chart.com/2010/08/github-stats-on-programming-languages.html
So this is the sell...
Why should you go out and build me a JavaScript type inferrer...
21% of the projects on GitHub are _labelled_ as JavaScript
2010-2012: http://t.arboreus.com/post/31469214663/visualizing-changes-in-popularity-rankings-of
* This is how the popularity of programming languages has changed (according to fairly
arbitrary measures) in the last two years.
* JavaScript is still on top.
LinkedIn numbers
914,000 people 2,000 people
JavaScript F#
in scale
Thanks to the
FunScript contributors
•Tomas Petricek
•Phillip Trelford
•James Freiwirth
•Robert Pickering
•Steffen Forkmann
If you’d like to contribute come and talk to me afterwards.
Summary
•FunScript compiles F# into JavaScript
•It is extensible: re-route any method call
•F# is the only statically typed language (that
I’m aware of) capable of taking advantage of
JavaScript libraries without FFI or code-gen