Skip to content

Instantly share code, notes, and snippets.

@miklund
Last active December 16, 2015 12:25
Show Gist options
  • Save miklund/73f8b743234208061efc to your computer and use it in GitHub Desktop.
Save miklund/73f8b743234208061efc to your computer and use it in GitHub Desktop.
2014-03-24 What is tail call optimization
# What is tail call optimization
# Author: Mikael Lundin
# Link: http://blog.mikaellundin.name/2014/03/24/tail-call-optimization.html
public static string IterativeJoin(IEnumerable<string> values)
{
var result = string.Empty;
foreach (var value in values)
{
// first
if (result == string.Empty)
{
result = value;
continue;
}
result += ", " + value;
}
return result;
}
let rec join res = function
| [] -> res
| hd :: tl when res = "" -> join hd tl
| hd :: tl -> join (res + ", " + hd) tl
.method public static
string join (
string res,
class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> _arg1
) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = (
01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00
)
// Method begins at RVA 0x20b0
// Code size 149 (0x95)
.maxstack 5
.locals init (
[0] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>,
[1] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>,
[2] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> tl,
[3] string hd,
[4] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> tl,
[5] string hd,
[6] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>,
[7] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> tl,
[8] string hd
)
// loop start
IL_0000: ldarg.1
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_0008: brfalse.s IL_002b
IL_000a: ldloc.0
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_0012: stloc.2
IL_0013: ldloc.1
IL_0014: call instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_HeadOrDefault()
IL_0019: stloc.3
IL_001a: ldarg.0
IL_001b: ldstr ""
IL_0020: call bool [mscorlib]System.String::Equals(string, string)
IL_0025: brfalse.s IL_0029
IL_0027: br.s IL_002e
IL_0029: br.s IL_0048
IL_002b: nop
IL_002c: ldarg.0
IL_002d: ret
IL_002e: ldloc.1
IL_002f: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_0034: stloc.s tl
IL_0036: ldloc.1
IL_0037: call instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_HeadOrDefault()
IL_003c: stloc.s hd
IL_003e: ldloc.s hd
IL_0040: ldloc.s tl
IL_0042: starg.s _arg1
IL_0044: starg.s res
IL_0046: br.s IL_0000
IL_0048: ldloc.0
IL_0049: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_004e: brfalse.s IL_0052
IL_0050: br.s IL_0054
IL_0052: br.s IL_0086
IL_0054: ldloc.0
IL_0055: stloc.s 6
IL_0057: ldloc.s 6
IL_0059: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_005e: stloc.s tl
IL_0060: ldloc.s 6
IL_0062: call instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_HeadOrDefault()
IL_0067: stloc.s hd
IL_0069: ldarg.0
IL_006a: ldstr ", "
IL_006f: call string [mscorlib]System.String::Concat(string, string)
IL_0074: ldloc.s hd
IL_0076: call string [mscorlib]System.String::Concat(string, string)
IL_007b: ldloc.s tl
IL_007d: starg.s _arg1
IL_007f: starg.s res
IL_0081: br IL_0000
// end loop
IL_0086: ldstr "C:\\Users\\Mikael\\Documents\\Visual Studio 2012\\Projects\\TailCallOptimized\\TailCallOptimized.Func\\Library1.fs"
IL_008b: ldc.i4.s 12
IL_008d: ldc.i4.s 19
IL_008f: newobj instance void [FSharp.Core]Microsoft.FSharp.Core.MatchFailureException::.ctor(string, int32,int32)
IL_0094: throw
} // end of method Func::join
let rec join_bad = function
| [] -> ""
| hd :: [] -> hd
| hd :: tl -> hd + ", " + (join_bad tl)
.method public static
string join_bad (
class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> _arg1
) cil managed
{
// Method begins at RVA 0x2050
// Code size 84 (0x54)
.maxstack 4
.locals init (
[0] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>,
[1] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>,
[2] string hd,
[3] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> tl,
[4] string hd
)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_0008: brfalse.s IL_001d
IL_000a: ldloc.0
IL_000b: stloc.1
IL_000c: ldloc.1
IL_000d: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_0012: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_0017: brtrue.s IL_001b
IL_0019: br.s IL_0024
IL_001b: br.s IL_002d
IL_001d: nop
IL_001e: ldstr ""
IL_0023: ret
IL_0024: ldloc.1
IL_0025: call instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_HeadOrDefault()
IL_002a: stloc.2
IL_002b: ldloc.2
IL_002c: ret
IL_002d: ldloc.1
IL_002e: call instance class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!0> class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_TailOrNull()
IL_0033: stloc.3
IL_0034: ldloc.1
IL_0035: call instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_HeadOrDefault()
IL_003a: stloc.s hd
IL_003c: ldloc.s hd
IL_003e: ldstr ", "
IL_0043: call string [mscorlib]System.String::Concat(string, string)
IL_0048: ldloc.3
IL_0049: call string TailCallOptimized.Func::join_bad(class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>)
IL_004e: call string [mscorlib]System.String::Concat(string, string)
IL_0053: ret
} // end of method Func::join_bad
public static string RecursiveJoin(IEnumerable<string> values, string result = "")
{
var first = values.FirstOrDefault();
if (first == null)
{
// values is empty list
return result;
}
var rest = values.Skip(1);
if (result == "")
{
// first
return RecursiveJoin(rest, first);
}
return RecursiveJoin(rest, result + ", " + first);
}
.method public hidebysig static
string RecursiveJoin (
class [mscorlib]System.Collections.Generic.IEnumerable`1<string> values,
[opt] string result
) cil managed
{
.param [2] = ""
// Method begins at RVA 0x21e8
// Code size 84 (0x54)
.maxstack 4
.locals init (
[0] string first,
[1] class [mscorlib]System.Collections.Generic.IEnumerable`1<string> rest,
[2] string CS$1$0000,
[3] bool CS$4$0001
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call !!0 [System.Core]System.Linq.Enumerable::FirstOrDefault<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: ldnull
IL_000a: ceq
IL_000c: ldc.i4.0
IL_000d: ceq
IL_000f: stloc.3
IL_0010: ldloc.3
IL_0011: brtrue.s IL_0018
IL_0013: nop
IL_0014: ldarg.1
IL_0015: stloc.2
IL_0016: br.s IL_0052
IL_0018: ldarg.0
IL_0019: ldc.i4.1
IL_001a: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Skip<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, int32)
IL_001f: stloc.1
IL_0020: ldarg.1
IL_0021: ldstr ""
IL_0026: call bool [mscorlib]System.String::op_Equality(string, string)
IL_002b: ldc.i4.0
IL_002c: ceq
IL_002e: stloc.3
IL_002f: ldloc.3
IL_0030: brtrue.s IL_003d
IL_0032: nop
IL_0033: ldloc.1
IL_0034: ldloc.0
IL_0035: call string TailCallOptimized.Program::RecursiveJoin(class [mscorlib]System.Collections.Generic.IEnumerable`1<string>, string)
IL_003a: stloc.2
IL_003b: br.s IL_0052
IL_003d: ldloc.1
IL_003e: ldarg.1
IL_003f: ldstr ", "
IL_0044: ldloc.0
IL_0045: call string [mscorlib]System.String::Concat(string, string, string)
IL_004a: call string TailCallOptimized.Program::RecursiveJoin(class [mscorlib]System.Collections.Generic.IEnumerable`1<string>, string)
IL_004f: stloc.2
IL_0050: br.s IL_0052
IL_0052: ldloc.2
IL_0053: ret
} // end of method Program::RecursiveJoin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment