I am working on a parser combinator library and found some behavior I couldn't explain. The first time I run the combinator it runs significantly slower than the second time that I run it. I repo'd the behavior with this small app (running Release with optimizations on)
let (>>=) first callback state =
let reply = first state
callback reply state
let time f =
let start = System.DateTime.Now
f()
printfn "%s" ((System.DateTime.Now - start).ToString())
[<EntryPoint>]
let main args =
let x1 state = "foo"
let compound =
x1 >>= fun i ->
x1 >>= fun j ->
x1 >>= fun a ->
x1 >>= fun b ->
x1 >>= fun c ->
x1 >>= fun d ->
x1 >>= fun e ->
x1 >>= fun f ->
x1 >>= fun j ->
fun _ -> [i;j;a;b;c;d;e;f]
time (fun () -> compound "a" |> ignore)
time (fun () -> compound "b" |> ignore)
time (fun () -> compound "c" |> ignore)
0
Running this output I get
00:00:00.0090009
00:00:00.0010001
00:00:00
Why is the first iteration so much slower than the second or third?
Edit, so I tried this out in C# as well. It runs faster, but the results are similar.
using System;
namespace fssharp
{
public delegate string Parser(string state);
public delegate Parser Callback(string result);
public class Combinator
{
public static Parser Combine(Parser p, Callback callback)
{
Parser r = state =>
{
var result = p(state);
return callback(result)(state);
};
return r;
}
public static string X1(string state)
{
return "foo";
}
}
class Program
{
static void Main(string[] args)
{
Parser comb = state =>
Combinator.Combine(Combinator.X1, result =>
Combinator.Combine(Combinator.X1, result2 =>
Combinator.Combine(Combinator.X1, result3 =>
Combinator.Combine(Combinator.X1, result4 =>
Combinator.Combine(Combinator.X1, result5 =>
Combinator.Combine(Combinator.X1, result6 =>
Combinator.Combine(Combinator.X1, result7 =>
Combinator.Combine(Combinator.X1, result8 =>
Combinator.Combine(Combinator.X1, result9 => s => result + result2 + result3 +result4 +result5 +result6 +result7+result8+result9)))
))))))(state);
var now = DateTime.Now;
comb("foo");
Console.WriteLine(DateTime.Now - now);
now = DateTime.Now;
comb("foo2");
Console.WriteLine(DateTime.Now - now);
}
}
}
This prints out
00:00:00.0030003
00:00:00
I'm now curious why C# is faster here