Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F#编译器抛出OutOfMemoryException_F#_Compiler Errors_Out Of Memory_Fsc - Fatal编程技术网

F#编译器抛出OutOfMemoryException

F#编译器抛出OutOfMemoryException,f#,compiler-errors,out-of-memory,fsc,F#,Compiler Errors,Out Of Memory,Fsc,我使用的项目包含许多从单个基类继承的类。在单元测试中,我需要按类型和数据比较收到的结果 当我在条件列表包含足够多不同条件的情况下使用类型匹配比较时,编译器抛出OutOfMemoryException 例如,下面的F#代码在编译过程中引发System.OutOfMemoryException(参数错误FS0193)(编译在引发异常之前花费了大约30秒) 当然,我可以将IEquatable接口添加到我的IBaseClass类中,这样可以避免使用这种匹配结构,或者将int-Kind成员(或enum)添

我使用的项目包含许多从单个基类继承的类。在单元测试中,我需要按类型和数据比较收到的结果

当我在条件列表包含足够多不同条件的情况下使用类型匹配比较时,编译器抛出OutOfMemoryException

例如,下面的F#代码在编译过程中引发System.OutOfMemoryException(参数错误FS0193)(编译在引发异常之前花费了大约30秒)

当然,我可以将IEquatable接口添加到我的IBaseClass类中,这样可以避免使用这种匹配结构,或者将int-Kind成员(或enum)添加到 IBaseClass接口并不是按类型匹配,而是按某些int值匹配

请注意,我曾尝试在MSVS2010和MSVS11beta中编译相同的项目,但出现了相同的编译器错误

问题:为什么编译器的OutOfMemoryException发生在我的情况下(是已知的编译器错误还是其他限制),我应该如何重新组织匹配条件以避免它?

更新当我将类放入有区别的联合并使用类似的匹配比较时,Fsc.exe毫无例外地编译项目

type AllClasses = 
    | ChildClass1 of IChildClass1 | ChildClass2 of IChildClass2 | ChildClass3 of IChildClass3 | ChildClass4 of IChildClass4 | ChildClass5 of IChildClass5 | ChildClass6 of IChildClass6
    | ChildClass7 of IChildClass7 | ChildClass8 of IChildClass8 | ChildClass9 of IChildClass9 | ChildClass10 of IChildClass10 | ChildClass11 of IChildClass11 | ChildClass12 of IChildClass12
    | ChildClass13 of IChildClass13 | ChildClass14 of IChildClass14 | ChildClass15 of IChildClass15 | ChildClass16 of IChildClass16 | ChildClass17 of IChildClass17 | ChildClass18 of IChildClass18 
    | ChildClass19 of IChildClass19 | ChildClass20 of IChildClass20

let AreEqual2 (original: AllClasses) (compareWith: AllClasses) : bool =
    match (original, compareWith) with
    | ChildClass1(a), ChildClass1(b) -> a = b
    | ChildClass2(a), ChildClass2(b) -> a = b
    | ChildClass3(a), ChildClass3(b) -> a = b
    | ChildClass4(a), ChildClass4(b) -> a = b
    | ChildClass5(a), ChildClass5(b) -> a = b
    | ChildClass6(a), ChildClass6(b) -> a = b
    | ChildClass7(a), ChildClass7(b) -> a = b
    | ChildClass8(a), ChildClass8(b) -> a = b
    | ChildClass9(a), ChildClass9(b) -> a = b
    | ChildClass10(a), ChildClass10(b) -> a = b
    | ChildClass11(a), ChildClass11(b) -> a = b
    | ChildClass12(a), ChildClass12(b) -> a = b
    | ChildClass13(a), ChildClass13(b) -> a = b
    | ChildClass14(a), ChildClass14(b) -> a = b
    | ChildClass15(a), ChildClass15(b) -> a = b
    | ChildClass16(a), ChildClass16(b) -> a = b
    | ChildClass17(a), ChildClass17(b) -> a = b
    | ChildClass18(a), ChildClass18(b) -> a = b
    | ChildClass19(a), ChildClass19(b) -> a = b
    | ChildClass20(a), ChildClass20(b) -> a = b
    | _ -> false

谢谢

在本例中,这是由F#编译器如何编译元组上的模式匹配引起的。我不完全确定您在这个特定问题中运行的确切时间,以及编译器使用其他方法的时间,但这里有一个解释,说明为什么在这种情况下它会失败

如果您编写了一个与示例中类似的模式匹配,编译器基本上会生成一个决策树,用于测试第一个模式的
原始
:?IChildClass1
),然后生成两个分支。第一个分支检查
compareWith
是否也是
IChildClass1
。如果是,则运行第一个案例。然后在两个分支中复制模式匹配的其余部分,因此您会得到类似的结果(您可以通过查看编译后的代码来检查这一点,以获得较少的用例):


这意味着生成代码的大小与此模式匹配中的案例数成指数比例。对于20种情况,编译器尝试创建2^20个分支,但失败(毫不奇怪)。

我假设您使用的是
IChildClass1-20
,仅用于说明,或者这是实际代码?我不认为编译器本身应该抛出一个
OutOfMemoryException
(但我没有答案)@Abel-是的,类名只是为了说明,类肯定有不同的名称。注意我的机器上,如果我在AreEqual中使用IChildClass1-18-项目是可编译的,19和更多-boom。。。谢谢你的解释。是的,我知道Fsc创建了2^20个分支,是什么导致了异常。但如果我将接口放入有区别的联合中(键入AllClasses=ChildClass1的ChildClass1 | ChildClass2的ChildClass2 | ChildClass3的ChildClass3…)并使用相同的元组匹配和判别联合-编译器编译项目时没有问题-因此,出于某种原因,编译后的if-else分支会根据类型进行比较,并与判别联合进行比较unions@Vitaliy正如我所说,我不知道编译器是如何决定要做什么的。然而,编译有区别的联合与测试接口是完全不同的。在DU的情况下,编译器知道只有一种情况可以保存。对于接口,一个值可以匹配多个模式(它可以实现多个接口)。我在HLVM中也有同样的错误@托马斯-谢谢你的解释,但修辞学问题是,为什么每个案例只有一个条件是不够的(如果(原文是IChildClass1&&compareWith是IChildClass1)案例#1…@正如你所说,一个条件就足够了。这只是模式匹配编译器的代码生成部分中的一个bug,它应该考虑子表达式以消除这种膨胀,但是作者显然忘记了在这个实例中。容易做,容易修理。
type AllClasses = 
    | ChildClass1 of IChildClass1 | ChildClass2 of IChildClass2 | ChildClass3 of IChildClass3 | ChildClass4 of IChildClass4 | ChildClass5 of IChildClass5 | ChildClass6 of IChildClass6
    | ChildClass7 of IChildClass7 | ChildClass8 of IChildClass8 | ChildClass9 of IChildClass9 | ChildClass10 of IChildClass10 | ChildClass11 of IChildClass11 | ChildClass12 of IChildClass12
    | ChildClass13 of IChildClass13 | ChildClass14 of IChildClass14 | ChildClass15 of IChildClass15 | ChildClass16 of IChildClass16 | ChildClass17 of IChildClass17 | ChildClass18 of IChildClass18 
    | ChildClass19 of IChildClass19 | ChildClass20 of IChildClass20

let AreEqual2 (original: AllClasses) (compareWith: AllClasses) : bool =
    match (original, compareWith) with
    | ChildClass1(a), ChildClass1(b) -> a = b
    | ChildClass2(a), ChildClass2(b) -> a = b
    | ChildClass3(a), ChildClass3(b) -> a = b
    | ChildClass4(a), ChildClass4(b) -> a = b
    | ChildClass5(a), ChildClass5(b) -> a = b
    | ChildClass6(a), ChildClass6(b) -> a = b
    | ChildClass7(a), ChildClass7(b) -> a = b
    | ChildClass8(a), ChildClass8(b) -> a = b
    | ChildClass9(a), ChildClass9(b) -> a = b
    | ChildClass10(a), ChildClass10(b) -> a = b
    | ChildClass11(a), ChildClass11(b) -> a = b
    | ChildClass12(a), ChildClass12(b) -> a = b
    | ChildClass13(a), ChildClass13(b) -> a = b
    | ChildClass14(a), ChildClass14(b) -> a = b
    | ChildClass15(a), ChildClass15(b) -> a = b
    | ChildClass16(a), ChildClass16(b) -> a = b
    | ChildClass17(a), ChildClass17(b) -> a = b
    | ChildClass18(a), ChildClass18(b) -> a = b
    | ChildClass19(a), ChildClass19(b) -> a = b
    | ChildClass20(a), ChildClass20(b) -> a = b
    | _ -> false
if (original is IChildClass1)
  if (compareWith is IChildClass1)
    case #1
  if (original is IChildClass2)
    if (compareWith is IChildClass2)
      case #2
    if (original is IChildClass3)
      (...)
else
  if (original is IChildClass2)
    if (compareWith is IChildClass2)
      case #2
    if (original is IChildClass3)
      (...)