F sharp is an up and coming programming language, allowing object-orientated, functional, imperitive approaches as well as a MATLAB-type envrionment and access to the .NET framework. For me, this makes it a very general-purpose language that one can use for pretty much everything. In this article I present a list of changes or additions that I would like to see in F Sharp extending these ideas - it is possible that some of them are implementable in a library to go on top of mllib.dll and fslib.dll, and this is a library I would like to create (say, mclib.dll.) Others are more fundamental and are to do with more the language itself. These I present first, the fourth of which is slightly deeper than the first three:
1. Export code from FSI
I have recently discovered F Sharp Interactive as use as a MATLAB-style envrionment for doing mathematical calculations, and also as, perhaps suprisingly, a form-designer. My F# environment is to use TextPad configured with the F Sharp syntax file (initially from Robert Picking's website, but extended as I've needed to to make more words blue :-) with a link to the F Sharp compiler tool. For form design, I've found FSI to be a good tool - load up FSI, and then line-by-line create a form and add controls to it, edit their properties in real-time as changes are viewed. I currently need to go back after I've done this and export all of the relevant commands, copy and pasting bits - it would be useful if FSI had the ability to export a file containing all of the code that was sucessfully compiled and run in the order it was input to FSI, hence removing this need for the necessary copying-and-pasting. I think this ability would have more general usage too as people can then experiment in FSI and export the code to a file when they've come up with the solution they need.
2. Accessor specification
Currently I believe FSharp compiles members to public members, and vals to internal fields. These are sensible defaults (although I'd maybe go for protected for vals) but it would be very useful to be able to optionally be able to specify the visibility of members and fields to the outside world, e.g. private member p.x, as you can in C#. F# supports the full object model apart from this, and including it would complete F#'s object-orientedness. In particular, if you wish to have private functions within classes used by multiple members, you either need to make them public or create them as local declarations multiple times - the former being a design issue, the latter reproducing code which is very anti-F#. Another possible addition here is support for class attributes such as sealed, private classes, internal classes.
3. Some left-associative . operator
In C#, I would often find myself writing a.d.e().f accessing a property of the result of a method of a property of object a. To write this in F#, one needs to write ((a.d).e()).f and if there is a long chain of these (as I have sometimes found in C#) this can become cumbersome. It would be useful to have a syntactic sugar left-associative . operator such as :, so that ((a.d).e()).f can be written a:d:e():f. Unforunately this clearly cannot be written as a higher-order function and so needs to be a language feature. Changing the associativity of . could also be a solution, but perhaps a more dramatic one.
4. Discriminated Union Compilation Enhancement
The previous two features have been concerned with object-orientated design and coding in F#. This one is too, but goes a little deeper. Clearly there is something very similar about
type a = B | C of string
with
member p.x() = match p with B -> "goorah" | C s -> s
end
and
class a with
abstract method p.x()
end
class Ba with
inherit a
override p.x() -> "goorah"
end
class Bc with
inherit a
val str : string
new(str) = { str = str }
override p.c = p.str
end
The former being a lot more concise and nice, of course. However, the first is not extentable, while the latter is, including being extendible in the rest of the .NET world. Now I've noticed that FSharp compiles discriminated unions, quite naturally, to an a class with a.B and a.C classes inheriting from a converting the first above vaguely into the second. It would be nice if when FSC compiles the discriminated union above it would need to split up the code in a.p() into two seperate parts in Ba.p() and Bc.p() as opposed to having all of the implementation in the superclass and a casting switch. My proposition is that it does this, compiling the discriminated union above into the same classes you would get if you were to compile the inheritance-based methods. Alternatively it may be desired that the a discriminated union be compiled to a sealed class, which may be wiser as clients extending discriminated unions could be undesirable. Either way, it would be nice if the compilation split up code of the form similar to p.x() = ... match p with ... into the subclasses (i.e. a._B) rather than using testing for casting into the subclasses in the superclass, as is currently being done, and it is this enhancement that I am proposing. Using a casting switch isn't a particularly elegant way of doing it, and causes (very, very, very) slight twinges of guilt whenever I use the discriminated union construct above knowing it will be compiled to this.
And now on to features that could in principle be implemented in a library to go on top of mllib and fslib, or indeed additions to the core libraries themselves. I would like to look at implementing some of these after I finish work towards the end of the summer:
5. Ocaml Standard Modules
The implementation of the standard ocaml library in mllib are currently incomplete. Implementing more of these would increase compatability with ocaml programs. Some of these would be relatively trivial to implement, e.g. Random, and some not so much, e.g. creating an implementation of the Graphics module using GDI+. In addition a few extra functions could be added to the current ones, e.g. for the List module take, drop, takewhile, dropwhile, fold_left2, map_index etc.
6. Full meta notation support
F Sharp currently allows meta programming through Quotations. I would like this MSP style to be fully supported, allowing the three constructs of MetaML - Brackets, Run and Escape and find direct equivalents of all three in F# to allow me to write a staged interpreter. Quotations allow the brackets <@ @> and we can use templates <@ 1 + _ @> for the escape idea, but there seems to be no obvious way of compiling and invoking quotations - that is a function run : 'a expr -> 'a. We need this for full MetaML support, and it seems to not quite yet exist in F# (it is mentioned briefly in Don's Leveraging .NET Meta-programming Components from F# paper.)
7. Coroutine notation support
Another paradigm that exists is that of co-routines, i.e. the Cocall, Resume and Yield constructs. Coroutines are a generalisation of generators and a specialisation of concurrent processes. It would be nice to have full support for these in F#, probably with a Coroutine data type that is implemented via threading. We would have
val cocall : (('b -> unit) -> 'b) -> 'b coroutine
val resume : 'b coroutine -> 'b
Note that this 'b coroutine object can be implemented via threading. (Note the above could (and should?) be generalised slightly to having yield return a value to the coroutine specified as an extra parameter of resume, giving a more symetric view of two processes.)
To create a co-routine that counts from a to b and then returns zero we can use
let count a b yield =
for i = a to b do
yield(i)
done; 0
And to print these
do let count = cocall (count a b) in
let r = ref 1
while (!r > 0) do
r := resume count;
print_int !r
done
I would also recommend that this coroutine type implements IEnumerable and such types, giving us full support for the yield concept of C# 2.0.
8. Extension of Maths library
FSI can currently be used, as I mentioned above, as a matlab-style maths libary. However it's currently only the basis of such, and some immediate but basic extra functions could be matrix inverses, determinants, polynomial and simultaneous equation sorting and numerical calculus (differentiate : (float -> float) -> float -> float.) Implementation of some of these ideas I feel would be also be a useful extension to F#.
9. Generic XML Parser
I recently found myself with complicated object or discriminated union hierarchies, and wanting to input one of these hirarchies into my program to run said program on it. A natural way to do this is by parsing an XML document, which is itself hierarchical, however it is tiresome to write an XML parser for each of these type of structures. Hence I thought it would be useful to have something that will automatically fill in the structure from the XML file using reflection. For example, from
<A>
<B c="1" d="3" />
<E r="2">
<G />
</E>
</A>
the equivalent of running the string new A(new B(1,3), new E(2, new G())) is created and passed to the program. Constructor n-ary overloading is very useful here (see my RayTracer project.) Furthermore, because of the way discriminated unions are compiled, we can use this directly as follows:
type A = B | C of string | D of A * A
then an A can be instantiated by interpreting
<A._D>
<A._B />
<A._C str="googoo" />
</A._D>
in the above way, which does so via the constructor new A._D(new A._B, new A._C("gogoo")). (Again this constructor is compiled and run at runtime using reflection.)
I have created an initial quick and dirty version of this, which works, in my RayTracer project, details of which shall or have already appeared elsewhere. To add additional functionality, since we sometimes have lists, I allow the user to pass in a dictionary which specifies whether the inner XML of an element is passed as multiple parameters, or a single parameter as a list e.g.
type A = B | C of string | D of A list
let dict = function "D" _ -> Some "A" | _ _ -> None
in myA = (xmlparse "myfile.xml" dict) :> A
val xmlparse : string -> (string -> int -> string option) -> obj
Here the third parameter is a function taking the name of the type, the number of parameters found before the inner XML is entered (i.e. attributes specified, for use in n-ary overloaded constructors - again see RayTracer) followed by None if the inner XML is to be parsed as continuing the list of parameters, or Some "T" if the inner XML is to be parsed as an instance of List<T>.
If this sounds confusing and/or too specific, check out my RayTracer project which uses this technology heavily. It should be obvious what is going on by looking at Documentation.txt (user documentation for the XML file) and the source code (class structure) and, if you need it, the examples. I think this is a useful tool in many situations and perhaps worth including in the general library.
10. Knowledge base support
A small backwards-chaining prolog-style knowledge base in F# could be useful. This is perhaps to specific for the F# library itself, but could be a sample and is just generally useful - it would be suitable for my mclib, and would contribute to the goal of making F# the general all around language for everything in a .NET environment allowing one to use it for logic programming too. We would have
type 'a kb = 'a horn_clause list
type 'a atomic = string * 'a term list
type 'a horn_clause = 'a atomic list * 'a atomic
type 'a term = Var of string | Lit of 'a | Function of string * 'a term
type 'a query = Atomic of 'a atomic | Not of 'a query | And of 'a query list | Or of 'a query list
val create : 'a kb
val tell : 'a kb -> 'a horn_clause -> 'a kb
val ask : 'a kb -> 'a query -> bool