Я написал несколько небольших функций разбора строк на F#, чтобы лучше понять F# и посмотреть, как с его помощью решать подобные задачи. Я пытаюсь пройти по строке и найти определенные символы с помощью рекурсии.
Логика работает, но сгенерированный IL-код релизной сборки (с включенными оптимизациями) выглядит странно, на мой взгляд. Так что я думаю, что есть лучший способ написать этот материал более производительно на F#.
Вот как выглядят функции парсинга:
let eatTag (input : string) index =
let len = input.Length
let nothing = 0, null, TagType.Open
// more functions used in the same way
// ...
let rec findName i =
if i >= len then nothing
else
let chr = input.[i]
if isWhitespace chr then
findName (i+1)
elif chr = '/' then
getName (i+1) (i+1) true
else getName (i+1) i false
let rec findStart i =
if i >= len then nothing
elif input.[i] = '<' then findName (i+1)
else findStart (i+1)
findStart index
Вот как выглядит сгенерированный IL-код для функции findStart:
// loop start
IL_0000: nop
IL_0001: ldarg.2
IL_0002: ldarg.1
IL_0003: blt.s IL_000e
IL_0005: ldc.i4.0
IL_0006: ldnull
IL_0007: ldc.i4.0
IL_0008: newobj instance void class [mscorlib]System.Tuple`3<int32, string, valuetype TagType>::.ctor(!0, !1, !2)
IL_000d: ret
IL_000e: ldarg.0
IL_000f: ldarg.2
IL_0010: call instance char [mscorlib]System.String::get_Chars(int32)
IL_0015: ldc.i4.s 60
IL_0017: bne.un.s IL_0024
IL_0019: ldarg.0
IL_001a: ldarg.1
IL_001b: ldarg.2
IL_001c: ldc.i4.1
IL_001d: add
IL_001e: call class [mscorlib]System.Tuple`3<int32, string, valuetype TagType> findName@70(string, int32, int32)
IL_0023: ret
IL_0024: ldarg.0
IL_0025: ldarg.1
IL_0026: ldarg.2
IL_0027: ldc.i4.1
IL_0028: add
IL_0029: starg.s i
IL_002b: starg.s len
IL_002d: starg.s input
IL_002f: br.s IL_0000
// end loop
Представление C# (ILSpy) для этой функции показывает следующий код, и именно поэтому я думаю, что делаю что-то не так. Очевидно, что аргументы функции каким-то образом присваиваются самой себе...?!
internal static Tuple<int, string, TagType> findStart@80(string input, int len, int i)
{
while (i < len)
{
if (input[i] == '<')
{
return findName@70(input, len, i + 1);
}
string arg_2D_0 = input;
int arg_2B_0 = len;
i++;
len = arg_2B_0;
input = arg_2D_0;
}
return new Tuple<int, string, TagType>(0, null, TagType.Open);
}
Ту же проблему можно увидеть и в других функциях, которые обрабатываются в стиле продолжения. Любые указатели на то, что я делаю или предполагаю неправильно, приветствуются :-)