Alice ML is a really futuristic programming language. All the goodness of Oz, plus a sophisticated type system.
Here, from the manual, is the complete code for a simple web server:
import structure TextIO from "x-alice:/lib/system/TextIO"
import structure Url from "x-alice:/lib/system/Url"
import structure Http from "x-alice:/lib/system/Http"
import structure HttpServer from "x-alice:/lib/system/HttpServer"
val documentRoot = "c:/temp"
val notFoundDocument = "The requested document could not be found\n"
fun documentHandler (request: Http.request) =
let
val relFile = Url.toString (Url.setQuery (#uri request, NONE))
val file = TextIO.openIn (documentRoot ^ relFile)
val body = TextIO.inputAll file
in
TextIO.closeIn file;
Http.makeResponse
{statusCode = 200, contentType = "text/plain", body}
end handle IO.Io {...} =>
Http.makeResponse
{statusCode = 404, contentType = "text/plain",
body = notFoundDocument}
val port = HttpServer.start NONE
val _ = HttpServer.register (Url.empty, documentHandler)
val _ = TextIO.print ("started server at port " ^
Int.toString port ^ "\n")
Did I mention the sophisticated type system? I believe I did. So where are all the type declarations? Ah, well…
Type inference is a way of determining the latent typing of a program’s terms, and detecting inconsistencies in usage. In statically type-checked languages without type inference, we have to declare up-front how a value is going to be used, and then the type-checker makes sure we’re as good as our word. In dynamically type-checked languages, we wait until run-time to find out we’ve goofed. But in the ML family of languages, to which Alice belongs, we get the static type-checking without having to supply type declarations (most of the time…) - so inconsistencies in usage are detected at compile-time even though we’ve not made any explicit commitments.