Tomas Petricek

Searching for new ways of thinking in programming & working with data

I believe that the most interesting work is not the one solving hard problems, but the one changing how we think about the world. I follow this belief in my work on data science tools, functional programming and F# teaching, in my programming languages research and I try to understand it through philosophy of science.

The Gamma

I'm working on making data-driven storytelling easier, more open and reproducible at the Alan Turing Institute.

Consulting

I'm author of definitive F# books and open-source libraries. I offer my F# training and consulting services as part of fsharpWorks.

Academic

I published papers about theory of context-aware programming languages, type providers, but also philosophy of science.

Tomas Petricek
  • Tomas Petricek
  • Home
  • F# Trainings
  • Talks and books
  • The Gamma
  • Academic

In the age of the web Typed functional-first programming revisited

Most programming languages were designed before the age of web. This matters because the web changes many assumptions that typed functional language designers tak for granted. For example, programs do not run in a closed world, but must instead interact with (changing and likely unreliable) services and data sources, communication is often asynchronous or event-driven, and programs need to interoperate with untyped environments like JavaScript libraries.

For dynamically-typed languages, the changing assumptions are not such a big issue (and e.g. Clojure with ClojureScript adapt extremely well), but how should statically-typed programming languages adapt to the modern world? In this article, I look at one possible answer that is inspired by the F# language and various F# libraries. In F#, we use type providers for integration with external information sources and for integration with untyped programming environments. We use lightweight meta-programming for targeting JavaScript and computation expressions for writing asynchronous code.

This blog post is a shorter version of a ML workshop paper that I co-authored earlier this year and you should read this more as a position statement. I'm not sure if F# and the solutions shown here are the best ones, but I think they highlight very important questions in programming language design that I very much see as unsolved.

The article has two sections. First, I'll go through a simple case study showing how F# can be used to build a client-side web app. Then, I'll discuss some of the implications for programming language design based on the example.

Case Study: Web-based data analytics

We write a web application, which lets the user compare university enrollment in a number of selected countries and regions around the world. The result runs as JavaScript and fetches data dynamically from the World Bank. The demo is simple and works with just a single data source, but it is a realistic app that could be built in context like data journalism to accompany an article. You can run the demo live on the FunScript web site. Here, I'll use a slightly modified version to better illustrate the issues. It builds a dashboard like this one:

Accessing World Bank data with type providers

The dashboard shows university enrollment and lets the user choose among a number of pre-defined countries. The list of countries is generated from a list in the source code that accesses countries using the WorldBank type provider from the F# Data library. The type provider exposes the individual countries as members of an object:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
type WorldBank = WorldBankDataProvider<Asynchronous=true>

let data = WorldBank.GetDataContext() 
let countries = 
  [ data.Countries.``European Union``
    data.Countries.``Czech Republic`` 
    data.Countries.``United Kingdom`` 
    data.Countries.``United States`` ]

The type provider connects to the World Bank and obtains a list of countries at compile-time and at edit-time (when using auto-completion in an editor). This means that the list is always up-to-date and we get a compile time error when accessing a country that no longer exists.

On the first line, we provide a static parameter Asynchronous to instruct the type provider to generate only non-blocking operations. This is necessary for a web-based application, because JavaScript only supports non-blocking calls (using AJAX callbacks) to fetch the data.

Interoperating with JavaScript libraries

To run the sample application on the client-side we use FunScript, which is a library that translates F# code to JavaScript. Aside from running as JavaScript, we also want to use standard JavaScript libraries, including jQuery for DOM manipulation and Highcharts for charting. FunScript comes with a type provider that imports TypeScript definitions for JavaScript libraries (the latest version of FunScript uses code generation rather than type providers for technical reasons):

1: 
2: 
type j = TypeScript.Api<"../files/jquery.d.ts">
type h = TypeScript.Api<"../files/highcharts.d.ts">

The d.ts files are type annotations created for the TypeScript language. Here, the type provider mechanism lets us leverage an existing effort for annotating common JavaScript libraries. The type provider analyses those definitions and maps them into F# types named j and h that contain statically typed functions for calling the JavaScript libraries. We use these to generate checkboxes that appear on the right.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
let jQuery (command:string) = 
  j.jQuery.Invoke(command) 

let infos = 
  countries |> List.map (fun country -> 
    let inp = jQuery("<input>").attr("type","checkbox") 
    jQuery("#panel").append([| inp |])
    jQuery("#panel").append([| box country.Name |]) 
    country.Name, country.Indicators, inp)

To manipulate the DOM, we are using the jQuery library in a way that is very similar to code that one would write in JavaScript. Note that members like \ident{append} and \ident{attr} are standard jQuery methods and the compiler sees them as ordinary object members (this blog is using F# Compiler Service and so you can hover over the identifiers and see the same tooltip that you would see in any F# editor).

Although the jQuery library is not perfect, it is a de facto standard in web development. The FunScript type provider makes it possible to integrate with it painlessly without explicitly specifying any FFI interface and without manual wrapping.

Note that we use a standard F# function \ident{List.map} to iterate over the countries. The function passed as an argument has a side-effect of creating the HTML elements, but it also returns a new list. The result is a list of `string Indicators jQuery$ values representing the country name, its indicators (for accessing the World Bank data) and the created DOM object representing the checkbox.

Loading data and updating the user interface

The main part of the sample program is a function render that asynchronously fetches data for selected countries and generates a chart. To keep the code simple, we iterate over the `infos list from the previous section and load data for countries one by one:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
let render () = async { 
  let head = "School enrollment, tertiary (% gross)" 
  let o = h.HighchartsOptions() 
  o.chart <- h.HighchartsChartOptions(renderTo = "plc") 
  o.title <- h.HighchartsTitleOptions(text = head) 
  o.series <- [| |] 

  for name, ind, check in infos do 
    if unbox<bool> (check.is(":checked")) then 
      let! vals = ind.``School enrollment, tertiary (% gross)`` 
      let data = vals |> Seq.map (fun (k,v) -> 
        [| number k; number v |]) |> Array.ofSeq 
      o.series.push(h.HighchartsSeriesOptions(data,name)) } 

We're using F# asynchronous workflows to fetch the data without blocking - when accessing the value of the School enrollment, tertiary (\% gross) indicator, we use the let! keyword. The indicator is a member exposed by the WorldBank type provider as an asynchronous computation (as requested by the static parameter). The rest of the code is mostly dealing with the DOM and the Highcharts library using the API imported by FunScript -- we iterate over all checkboxes and generate a new chart series for each checked country.

Two notable points here are that async translated to JavaScript is restricted to a single thread, which is not the case for ordinary F# code and that the HighchartOption object preserves some of the underlying JavaScript semantics - we create an empty array o.series and then add elements to it using o.series.push which would not be possible in ordinary F# code.

Finally, the last part of the example code registers event handlers that redraw the chart when the checkbox is clicked:

1: 
2: 
for _, _, check in infos do 
  check.click(fun _ -> Async.StartImmediate(render()))

The click operation (exposed by jQuery) takes a function that should be called when the event occurs. Calling it is a side-effectful operation that registers the handler. As render is an asynchronous operation, we invoke it using the StartImmediate primitive from the F# library, which starts the computation without waiting for the result (the only way to start a non-blocking operation in JavaScript).

Analysis: Learning from the case study

The case study is quite simple, but it shows that you can build a simple interactive visualization in just 30 lines of F#. It also illustrates many of the important issues that we face when working with the web. There are a number of good things that we get to keep from statically-typed functional-first programming style:

  • Type inference and static typing can be extended from closed-world data types to open-world types. The sample is statically checked (including data from the World Bank) without explicit type annotations and the type information is also available in the editor for exploration.
  • Nice functional constructs (lists, higher-order functions like map) from F# can be used for client-side web development - they get translated to JavaScript and run in the browser.
  • We can also use F# features like asynchronous workflows for writing non-blocking code (for requesting data from the World Bank) without error-prone explicit callbacks.
  • We are able to (relatively) painlessly call Highcharts and jQuery. No explicit wrapping or importing of individual functions and types was necessary. Despite the differences between the F# and JavaScript object model, the code is close to idiomatic F#.

There are also a few things that are a bit unexpected when you look at the example through the perspective of traditional statically-typed languages:

  • The World Bank type provider lifts information about countries to the type level. If Czech Republic disappears from the world, the code will no longer compile.
  • The TypeScript language is unsound and so importing types from TypeScript could introduce an unsoundness into the F# code.
  • When compiling F# to JavaScript, the FunScript library does not fully preserve the semantics of F#. For example, numerical types behave as in JavaScript and asynchronous workflows run on a single thread.

The approach that you can use with F# often has both positive and negative side. For example, we can easily access data from World Bank, but it means that we have to give up some of the safety properties. The approach highlighted here is just one possible and the case study shows that it works in practice, but there might be other options.

I want to spend the rest of this section discussing some of the important implications for the design of statically-typed programming languages of the future. If languages want to provide the user experience showed in the above case study, what do they need to look like?

Integrating with external data sources

Statically-typed programming languages are designed with the assumption that the program runs in a world that is closed - all we can call and access comes from a library that is defined within the world of the language. This is not the case. Even before the web, applications need to perform I/O, but the web makes this even more obvious. In terms of programming language theory, the starting point of a programming language needs to change as follows:

(Empty world)
(Type providers)

The syntax \(\Gamma \vdash e : \tau\) denotes that a program \(e\) has a type \(\tau\) in a context defined by \(\Gamma\). The context typically contains variables, library functions and so on. With type providers, the context is much richer - a type provider is like a projection \(\pi\) that can import anything from the outside world into the programming language context.

The World Bank provider is an interesting example - it is designed for one specific data source (in contrast to the XML, JSON and CSV type providers). The projection it implements generates a type Countries with individual countries as members. Each country returns a value of Indicators that is also generated and it contains all World Bank indicators as members. The type provider is erased during compilation and replaced with runtime implementation as follows:

1: 
2: 
3: 
4: 
5: 
〚 data.``Czech Republic`` 〛=
    data.GetCountries().GetCountry("CZE")
  
〚 cz.``School enrollment, tertiary (% gross)`` 〛=
    cz.AsyncGetIndicator("SE.TER.ENRR")

The underlying operations (GetCountry, AsyncGetIndicator) are normal functions of an underlying runtime library. The type provider generates a light layer on top of this runtime library. An important thing is that the type provider generates code that refers to the country and indicator using a code (even though the type we see uses a more friendly name). Knowing this helps us understand the properties of the type povider:

  • If you are editing or compiling code that uses the type provider offline, the type provider will not be able to obtain the list of countries and indicators and so the projection \(\pi\) will fail (although the World Bank provider caches the schema on the first use).

  • When a country or indicator is renamed, the compiled code will continue to work, because the code still exists. However, recompilation will fail as the member name will be different.

  • If a country or indicator disappears, we will get a runtime failure when running existing compiled code. However, we will also get a type-checking error when recompiling the code - this is useful, because it prevents us from compiling code that would not work at runtime.

Using type providers to access external data certainly relaxes traditional type safety conditions. However, rather than introducing new unsafety, this just makes existing issues more apparent - if we wrote data.GetCountries().GetCountry("CZE"), we would get the same runtime error if Czech Republic disappeared. With type providers, this is now reflected in the type system, but with a twist that the type safety depends on the external data source.

Integrating with external environments

The case study uses type providers not just for external data sources, but also for integration with external execution environments - in particular, for importing definitions of JavaScript libraries. Another example of this kind of use is the R type provider that allows F# programs to call R functions.

The TypeScript type provider makes it possible to use jQuery and Highcharts almost as if they were native F# libraries, but the word almost is important here, because there is always going to be some mismatch between F# and any other external environment. Let's look at a part of the jquery.d.ts file that defines TypeScript types for jQuery:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
declare var jQuery : JQueryStatic;
interface JQueryStatic { 
  (selector : string, context? : any) : JQuery; 
} 
interface JQuery { 
  attr(attributeName : string) : string; 
  attr(attributeName : string, value : any) : JQuery; 
}  

The snippet defines a global variable jQuery which is an invokable object that returns JQuery value with an overloaded attr method. When mapping this to F#, we have to solve the following issues:

  • Type providers cannot provide global variables and so TypeScript type provider exposes global variables as static members
  • F# does not support invokable objects and so the type provider generates an explicit Invoke method which is mapped to object invocation.
  • F# does support optional parameters and overloads, so those are mapped to the F# equivalent (but if we were in, say, Haskell, we would have to do something else here).

With F# used as the host language, we are quite fortunate, because we get many functional language features but also many object-oriented features. This means that when mapping external environments into F#, there is often a corresponding construct in F#. However, there are still things that cannot be expressed in F# and for those, we have to find alternative encoding.

Alternatives for environment integration

There are two alternatives for interoperating external worlds that you can find in other X-to-JavaScript compilers:

  • Explicit mapping. If we want to call some JavaScript function, we have to provide an explicit mapping for it. We define an F# stub (it could be a function with no body or an interface) that is then mapped to JavaScript. This could use annotations (.NET attributes) or follow some convention. In FunScript, you get this with the JSEmit attribute and it is useful for small snippets, but it hardly scales for anything as large as jQuery.

  • Minimal mapping. An interesting option that some X-to-JavaScript compilers use is to mostly ignore the target environment. Instead, they map many source X libraries into JavaScript and would rely only on core DOM (with a wrapper written in X on top of it) rather than on JQuery which would not be idiomatic X library.

I believe that modern programming languages will increasingly need to be able to access external environments and so the F# approach with type providers is an important direction. After all, we need to access rich visualization libraries built in the JavaScript environment or rich statistical functionality available in R.

Mixing stronger and weaker type systems

Another interesting issue that becomes apparent in the case study is that we are mixing the F# type system with a type system of TypeScript. Now, the TypeScript type system is deliberately unsound. Does this mean that we are breaking the soundness of F# too? This is not really happening directly in this case, because we are just importing TypeScript library definitions - but a JavaScript library we are calling can certainly return an unexpected value.

In a heterogeneous environment, we will always be mixing type systems that have different strength or expressivity.

  • Weaker target type systems. When interoperating with a weaker type system, a type provider may need to map more types to a general type like obj in F#. This makes the provided operations harder to use because the target language allows more flexibility. In our example, TypeScript has a type any that can be used in any context - F# does not allow this and so we had to explicitly use the unsafe unbox<bool> to treat obj as bool.

  • Stronger target type sytems. If the imported language has stronger type system than F#, the type provider will have to drop some information. This can be done safely when reading information, but not when passing values to the target language (in that case, the type provider would have to generate additional runtime checks).

When interoperating with another environment, there will always be some mismatch. We either need to reconstruct some information (e.g. using jquery.d.ts annotation file), or through some other mechanism (R provider uses runtime reflection). With F#, we have the obj type and unsafe features like unbox, so this gives us at least some way of encoding unsafe operations, but arguably, having something akin to C# dynamic would sometimes be useful.

Heterogeneous execution

Finally, the last interesting aspect of the case study is that we were able to use a large number of standard F# language features and libraries even though the code was translated and executed as JavaScript and the JavaScript semantics differ in a number of ways. For example, we used ordinary F# async workflows and wrote:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
let render () = async { 
  let o = h.HighchartsOptions() 
  (Initialize Highcharts options)
  
  for name, ind, check in infos do 
    if unbox<bool> (check.is(":checked")) then 
      let! vals = ind.``School enrollment, tertiary (% gross)`` 
      let data = (Convert values to array)
      o.series.push(h.HighchartsSeriesOptions(data,name)) } 

Strictly speaking, F# asynchronous workflows cannot be translated to JavaScript. They run in parallel and are scheduled using thread pool, which is not available when running code as JavaScript and they have other properties (they can capture SynchronizationContext of the thread, etc.)

The alternative would be to define a JavaScript-based version of asynchronous workflows, say jsasync { .. } and require the developer to write code using this semantically correct version instead. This makes the code clumsier, but arguably more correct. However, the semantic differences with JavaScript go much further. JavaScript has different exceptions and even different numerical type. To be fully correct, we'd have to use jsfloat, jsexception and so on!

The example in the case study follows the less correct path - it maps ordinary F# async workflows to the closest thing that can be done in JavaScript. It provides mapping for Async.StartImmediate (which has close equivalent in the browser) but not for Async.Start (which would require a background thread).

F# numerical types are mapped to native JS numerical types with all the potential issues this brings (floating point numbers use JavaScript semantics). Also, F# arrays are mapped to JavaScript arrays, which allows us to use some of the JavaScript semantics and use o.series.push to append element to an array (which cannot be done in pure F#).

Conclusions: Languages for the modern age

This article uses the "age of the web" phrase, because it nicely illustrates many of the important problems that modern languages face. More than before, we need to access data and call services from the outside world (that cannot be fully trusted) and we need to interoperate with other execution environments (which have different features and different levels of safety).

Programming languages that we use today were not designed with these constraints in mind. They assume that programs live in a closed world (where everything has been created in the same language or comes from the same runtime).

Integrating with the open world is much easier for dynamically-typed languages like Clojure with ClojureScript. In the world of statically-typed languages, the situation is much harder - and I think that the F# type provider mechanism is the first step towards languages that give the useful benefits of (smart) static type systems while being a good fit for solving problems that come with modern kinds of applications.

Going over the case study and the analysis, I think there are two key points.

Flexibility with escape options

First, when we want to interoperate with outside environments, the host language needs to provide a lot of flexibility. In case of F#, you get support for both functional and object-oriented style. This means that more of the outside world can be mapped to a close construct in the F# world. I believe that this is crucial - a language can practically interoperate with the outside world if the mapping is not too cumbersome.

The other aspect is that if the host language is strict in some way, it needs to provide some escaping mechanism. F# does this with the obj type and unbox. This works, but there is probably more that could be done here. (And there are also other situations where an escape mechanism would help.)

Relativized safety and semantics

Does the flexibility and the escaping hurt the nice safety properties of the host language? If you are a strict theoretician, then the answer is of course yes. But I think there is a useful middle ground here. Using F# as we did in the case study here, we get a nice property:

When you use the core subset of F#, the program will behave according to the usual core F# semantics and you are guaranteed the usual core F# properties. Using non-core features in other environments may have different semantics and different properties.

To an extent, you can already see this with F# when working with .NET. F# types do not allow the null value, but .NET types do. When you use functional style with F#, you do not need type annotations, but when you use objects, you do. So for F#, even .NET is an outside environment that breaks some of the language properties.

Summary

I think we need to give up on the idea that programming languages should be designed for one controlled execution environment. There should be a core with certain core properties (like the ML core of F#) with additional layers that are more flexible and adaptable to allow running in the heterogenous modern world. How exactly this should be done, that's an interesting open question, but I think F# with type providers shows one important component of the solution.

Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Data

--------------------
namespace Microsoft.FSharp.Data
namespace FunScript
namespace FunScript.TypeScript
type WorldBank = WorldBankDataProvider<...>

Full name: Typed-revisited.WorldBank
type WorldBankDataProvider

Full name: FSharp.Data.WorldBankDataProvider


<summary>Typed representation of WorldBank data with additional configuration parameters. See http://www.worldbank.org for terms and conditions.</summary>
                        <param name='Sources'>The World Bank data sources to include, separated by semicolons. Defaults to `World Development Indicators;Global Financial Development`.
                        If an empty string is specified, includes all data sources.</param>
                        <param name='Asynchronous'>Generate asynchronous calls. Defaults to false.</param>
val data : WorldBankDataProvider<...>.ServiceTypes.WorldBankDataService

Full name: Typed-revisited.data
WorldBankDataProvider<...>.GetDataContext() : WorldBankDataProvider<...>.ServiceTypes.WorldBankDataService
val countries : WorldBankDataProvider<...>.ServiceTypes.Country list

Full name: Typed-revisited.countries
property WorldBankDataProvider<...>.ServiceTypes.WorldBankDataService.Countries: WorldBankDataProvider<...>.ServiceTypes.Countries
type j = Api<...>

Full name: Typed-revisited.j
type Api

Full name: FunScript.TypeScript.Api
type h = Api<...>

Full name: Typed-revisited.h
val jQuery : command:string -> Api<...>.JQuery

Full name: Typed-revisited.jQuery
val command : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
property Api<...>.jQuery: Api<...>.JQueryStatic
Api<...>.JQueryStatic.Invoke() : Api<...>.JQuery
Api<...>.JQueryStatic.Invoke(selector: string) : Api<...>.JQuery
Api<...>.JQueryStatic.Invoke(element: Api<...>.Element) : Api<...>.JQuery
Api<...>.JQueryStatic.Invoke(elementArray: Api<...>.Element []) : Api<...>.JQuery
Api<...>.JQueryStatic.Invoke(object: Api<...>.JQuery) : Api<...>.JQuery
Api<...>.JQueryStatic.Invoke(func: Api<...>.Function) : Api<...>.JQuery
Api<...>.JQueryStatic.Invoke(selector: string, context: obj) : Api<...>.JQuery
val infos : (string * WorldBankDataProvider<...>.ServiceTypes.Indicators * obj) list

Full name: Typed-revisited.infos
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member GetSlice : startIndex:int option * endIndex:int option -> 'T list
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val country : WorldBankDataProvider<...>.ServiceTypes.Country
val inp : obj
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
property Runtime.WorldBank.Country.Name: string
property WorldBankDataProvider<...>.ServiceTypes.Country.Indicators: WorldBankDataProvider<...>.ServiceTypes.Indicators


<summary>The indicators for the country</summary>
val render : unit -> Async<unit>

Full name: Typed-revisited.render
val async : AsyncBuilder

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val head : string
val o : Api<...>.HighchartsOptions
property Api<...>.HighchartsOptions.chart: Api<...>.HighchartsChartOptions
type HighchartsChartOptions =
  new : unit -> HighchartsChartOptions
  member alignTicks : bool with get, set
  member animation : HighchartsBoolOrAnimation with get, set
  member backgroundColor : HighchartsColorOrGradient with get, set
  member borderColor : string with get, set
  member borderRadius : float with get, set
  member borderWidth : float with get, set
  member className : string with get, set
  member defaultSeriesType : string with get, set
  member events : HighchartsChartEvents with get, set
  ...

Full name: FunScript.TypeScript.Api,files="../files/highcharts.d.ts".HighchartsChartOptions
property Api<...>.HighchartsOptions.title: Api<...>.HighchartsTitleOptions
type HighchartsTitleOptions =
  new : unit -> HighchartsTitleOptions
  member align : string with get, set
  member floating : bool with get, set
  member margin : float with get, set
  member style : HighchartsCSSObject with get, set
  member text : string with get, set
  member useHTML : bool with get, set
  member verticalAlign : string with get, set
  member x : float with get, set
  member y : float with get, set

Full name: FunScript.TypeScript.Api,files="../files/highcharts.d.ts".HighchartsTitleOptions
property Api<...>.HighchartsOptions.series: Api<...>.HighchartsSeriesOptions []
val name : string
val ind : WorldBankDataProvider<...>.ServiceTypes.Indicators
val check : obj
val unbox : value:obj -> 'T

Full name: Microsoft.FSharp.Core.Operators.unbox
type bool = System.Boolean

Full name: Microsoft.FSharp.Core.bool
val vals : seq<obj * obj>
val data : obj [] []
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val k : obj
val v : obj
module Array

from Microsoft.FSharp.Collections
val ofSeq : source:seq<'T> -> 'T []

Full name: Microsoft.FSharp.Collections.Array.ofSeq
type HighchartsSeriesOptions =
  new : unit -> HighchartsSeriesOptions
  member data : obj with get, set
  member index : float with get, set
  member legendIndex : float with get, set
  member name : string with get, set
  member stack : obj with get, set
  member ``type`` : string with get, set
  member xAxis : float with get, set
  member yAxis : float with get, set

Full name: FunScript.TypeScript.Api,files="../files/highcharts.d.ts".HighchartsSeriesOptions
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
static member Async.StartImmediate : computation:Async<unit> * ?cancellationToken:System.Threading.CancellationToken -> unit
val o : obj
type HighchartsOptions =
  new : unit -> HighchartsOptions
  member chart : HighchartsChartOptions with get, set
  member colors : string [] with get, set
  member credits : HighchartsCreditsOptions with get, set
  member exporting : HighchartsExportingOptions with get, set
  member ``global`` : HighchartsGlobalOptions with get, set
  member labels : HighchartsLabelsOptions with get, set
  member lang : HighchartsLangOptions with get, set
  member legend : HighchartsLegendOptions with get, set
  member loading : HighchartsLoadingOptions with get, set
  ...

Full name: FunScript.TypeScript.Api,files="../files/highcharts.d.ts".HighchartsOptions
o.chart <- h.HighchartsChartOptions(renderTo = "plc")
  o.title <- h.HighchartsTitleOptions(text = head)
  o.series <- [| |]
vals |> Seq.map (fun (k,v) ->
        [| number k; number v |]) |> Array.ofSeq

Published: Wednesday, 9 September 2015, 5:14 PM
Author: Tomas Petricek
Typos: Send me a pull request!
Tags: f#, type providers, web, functional programming, research

Contact & about

This site is hosted on GitHub and is generated using F# Formatting and DotLiquid. For more info, see the website source on GitHub.

Please submit issues & corrections on GitHub. Use pull requests for minor corrections only.

  • Twitter: @tomaspetricek
  • GitHub: @tpetricek
  • Email me: tomas@tomasp.net

Blog archives

October 2020 (1),  July 2020 (1),  April 2020 (2),  December 2019 (1),  February 2019 (1),  November 2018 (1),  October 2018 (1),  May 2018 (1),  September 2017 (1),  June 2017 (1),  April 2017 (1),  March 2017 (2),  January 2017 (1),  October 2016 (1),  September 2016 (2),  August 2016 (1),  July 2016 (1),  May 2016 (2),  April 2016 (1),  December 2015 (2),  November 2015 (1),  September 2015 (3),  July 2015 (1),  June 2015 (1),  May 2015 (2),  April 2015 (3),  March 2015 (2),  February 2015 (1),  January 2015 (2),  December 2014 (1),  May 2014 (3),  April 2014 (2),  March 2014 (1),  January 2014 (2),  December 2013 (1),  November 2013 (1),  October 2013 (1),  September 2013 (1),  August 2013 (2),  May 2013 (1),  April 2013 (1),  March 2013 (1),  February 2013 (1),  January 2013 (1),  December 2012 (2),  October 2012 (1),  August 2012 (3),  June 2012 (2),  April 2012 (1),  March 2012 (4),  February 2012 (5),  January 2012 (2),  November 2011 (5),  August 2011 (3),  July 2011 (2),  June 2011 (2),  May 2011 (2),  March 2011 (4),  December 2010 (1),  November 2010 (6),  October 2010 (6),  September 2010 (4),  July 2010 (3),  June 2010 (2),  May 2010 (1),  February 2010 (2),  January 2010 (3),  December 2009 (3),  July 2009 (1),  June 2009 (3),  May 2009 (2),  April 2009 (1),  March 2009 (2),  February 2009 (1),  December 2008 (1),  November 2008 (5),  October 2008 (1),  September 2008 (1),  June 2008 (1),  March 2008 (3),  February 2008 (1),  December 2007 (2),  November 2007 (6),  October 2007 (1),  September 2007 (1),  August 2007 (1),  July 2007 (2),  April 2007 (2),  March 2007 (2),  February 2007 (3),  January 2007 (2),  November 2006 (1),  October 2006 (3),  August 2006 (2),  July 2006 (1),  June 2006 (3),  May 2006 (2),  April 2006 (2),  December 2005 (1),  July 2005 (4),  June 2005 (5),  May 2005 (1),  April 2005 (3),  March 2005 (3),  January 2005 (1),  December 2004 (3),  November 2004 (2), 

License

Unless explicitly mentioned, all articles on this site are licensed under Creative Commons Attribution Share Alike. All source code samples are licensed under the MIT License.

CC License logo