ICFP Programming Contest 2014
icfpcontest.org139 pointsby thoughtpolice18 comments
if thing then error "bad things" else 10*2
I can change this to: let x = error "bad things" if thing then x else 10*2
You cannot do this in a non lazy language. Well, you can, but it gets miserable pretty quick. Furthermore this applies to any subexpression; suppose I have a program: h <- openThing "foo"
doStuff h
... some more stuff ...
undoStuff h
closeThing h
I can change this to:
let begin f =
h <- openThing f
doStuff h
let end h =
undoStuff h
closeThing h
h <- begin "foo"
... some more stuff ...
end h
Again, this is not valid if your language is strict. But these patterns are very obvious and common when you can freely rearrange any expression. Then you can see the final abstraction easily: let withThing x f =
h <- openThing f
doStuff h
f
undoStuff h
closeThing h
let stuff = ... do some stuff ...
withThing "foo" stuff
This particular point requires a lot of experience to truly appreciate in practice IMO. But in practice it means you can freely move code anywhere at no cost, even any I/O code, so you can very easily abstract over it like above. In non-lazy languages, this becomes significantly more tedious. ids := getAllUserIds -- fetch from source 1 time
foreach id as ids {
x <- getUserFriends id -- N queries, 1 for each id
...
}
Which is simple and naive, yet Haxl can optimize this automatically into a program that will A) batch all of the data accesses together (so instead of running N queries for each ID, each query gets batched into one request for a range of users), B) automatically access each data source concurrently with no programmer intervention, so when queries can execute in parallel they do so, and C) cache the results, so that you aren't re-querying already fetched data.
That's a shame, they're excellent machines... I guess we'll have to find another sponsor soon.