Wolfram mathematica 防止Mathematica中运行时错误的雪崩

Wolfram mathematica 防止Mathematica中运行时错误的雪崩,wolfram-mathematica,Wolfram Mathematica,我遇到的一个典型情况是,当笔记本电脑超出了几个函数时——我计算一个表达式,但没有得到正确的答案,而是发出嘟嘟声,然后是几十个无用的警告,接着是“进一步输出的…将被抑制” 我发现有一件事很有用——在函数中使用类似Python的“assert”来增强内部一致性。还有其他建议吗 Assert[expr_, msg_] := If[Not[expr], Print[msg]; Abort[], None] 编辑11/14 警告雪崩的一般原因是子表达式的计算结果为“坏”值。这会导致父表达式的计算结果为“

我遇到的一个典型情况是,当笔记本电脑超出了几个函数时——我计算一个表达式,但没有得到正确的答案,而是发出嘟嘟声,然后是几十个无用的警告,接着是“进一步输出的…将被抑制”

我发现有一件事很有用——在函数中使用类似Python的“assert”来增强内部一致性。还有其他建议吗

Assert[expr_, msg_] := If[Not[expr], Print[msg]; Abort[], None]
编辑11/14 警告雪崩的一般原因是子表达式的计算结果为“坏”值。这会导致父表达式的计算结果为“坏”值,并且这种“坏”会一直传播到根。一路上经过评估的内置程序会注意到问题并发出警告。“Bad”可能意味着一个头部错误的表达式、元素数量错误的列表、负定矩阵而不是正定矩阵等。通常,它与父表达式的语义不符

解决这个问题的一种方法是重新定义所有函数,以返回未计算的“错误输入”。这将处理由内置生成的大多数消息。执行“部件”等结构操作的内置程序仍将尝试评估您的值,并可能产生警告


将调试器设置为“消息中断”可以防止错误雪崩,尽管始终打开调试器似乎是一种过火的行为

这里的问题本质上是一种类型。一个函数产生一个错误的输出(不正确的类型),然后输入到许多后续函数中,产生大量错误。虽然Mathematica不像其他语言那样有用户定义的类型,但您可以对函数参数进行模式匹配,而无需做太多工作。如果匹配失败,函数将不计算,因此不会发出错误的蜂鸣音。语法的关键部分是“/”,它位于一些代码的末尾,然后是测试。一些示例代码(输出如下)

如果测试更简单,则有另一个符号执行类似的模式测试“?”并紧跟在模式/函数声明中的参数之后。另一个例子如下

Input:
Average[x_] := Mean[x] /; VectorQ[x, NumericQ]
Average[{1, 2, 3}]
Average[$Failed]

Output:
2
Average[$Failed]
Input:
square[x_?NumericQ] := x*x
square[{1, 2, 3}]
square[3]

Output:
square[{1, 2, 3}]
9

它可以帮助定义一个catchall定义,以获取错误条件并以有意义的方式报告它:

f[x_?NumericQ] := x^2;
f[args___] := Throw[{"Bad Arguments: ", Hold[f[args]]}]
因此,您的顶级呼叫可以使用Catch[],也可以让它冒泡:

In[5]:= f[$Failed]

During evaluation of In[5]:= Throw::nocatch: Uncaught Throw[{Bad Args: ,Hold[f[$Failed]]}] returned to top level. >>

Out[5]= Hold[Throw[{"Bad Args: ", Hold[f[$Failed]]}]]

我希望得到的是一种方法,可以定义一个通用过程来捕获错误传播,而无需立即彻底改变我编写函数的方式,尤其是不添加大量类型

下面是一个尝试:

funcDef = t_[args___]  :c-:  a_ :> ReleaseHold[Hold[t[args] := 
                         Check[a, Print@Hold[a]; Abort[]]]];
Clear@v;
v[x_, y_] :c-: Sin[x/y] /. funcDef;
?v
v[2, 3]
v[2, 0] 
:c-:当然是Esc c-Esc,一个未使用的符号(\[CircleMinus]),但任何人都会这样做

输出:

Global`v
v[x_,y_]:=Check[Sin[x/y],Print[Hold[Sin[x/y]]];Abort[]]

Out[683]= Sin[2/3]

During evaluation of In[679]:= Power::infy: Infinite expression 1/0 encountered. >>

During evaluation of In[679]:= Hold[Sin[2/0]]

Out[684]= $Aborted
我们改变的是

       v[x_, y_] := Sin[x/y]

这几乎满足了我的前提

编辑

也许为函数添加一个“裸”定义也很方便,它不需要进行错误检查。我们可以将funcDef规则更改为:

funcDef = 
     t_[args___]  \[CircleMinus] a_ :> 

            {t["nude", args] := a, 

             ReleaseHold[Hold[t[args] := Check[a, Print@Hold[a]; Abort[]]]]
            };  
争取

 v[x_, y_] :c-: Sin[x/y] /. funcDef;  
这个输出

v[nude,x_,y_]:=Sin[x/y]

v[x_,y_]:=Check[Sin[x/y],Print[Hold[Sin[x/y]]];Abort[]]

正如其他人所指出的,有三种方法可以一致地处理错误:

  • 正确键入参数并设置函数运行的条件
  • 正确、一致地处理产生的错误,以及
  • 简化方法以应用这些步骤
  • 如前所述,正确键入函数将有很大帮助。不要忘了的
    形式,因为用这种形式表达某些模式有时更容易,例如
    x:{{{{{,}..}
    。显然,当这还不够时,
    PatternTest
    s()和
    Condition
    s()是一种方法。Samdram很好地涵盖了这一点,但我想补充一点,您可以通过纯函数创建自己的模式测试,例如
    f[x#?(Head[#]==List&]
    相当于
    f[x#List]
    。注意,当使用纯函数的符号和形式时,括号是必要的

    处理生成的错误的最简单方法显然是关闭,或者更局部地关闭。在大多数情况下,我们都同意完全关闭我们不想要的消息是一个坏主意,但是当你知道你正在做的事情会引起抱怨,但在其他方面是正确的时,
    Quiet
    非常有用

    Throw
    Catch
    有它们的位置,但我觉得它们应该只在内部使用,您的代码应该通过设施来传达错误。创建消息的方式与设置使用情况消息的方式相同。我相信连贯错误策略的关键可以使用函数来构建

    例子 我的代码中的一个示例是
    OpenAndRead
    ,它可以在中止读取操作时防止离开打开的流,如下所示:

    OpenAndRead[file_String, fcn_]:=
    Module[{strm, res},
      strm = OpenRead[file];
      res = CheckAbort[ fcn[strm], $Aborted ];
      Close[strm];
      If[res === $Aborted, Abort[], res] (* Edited to allow Abort to propagate *)
    ]
    
    MakeCheckedReader /: 
        SetDelayed[MakeCheckedReader[fcn_Symbol, symbols___], a_] :=
        Quiet[(fcn[file_String, symbols] := OpenAndRead[file, fcn[#, symbols] &];
               SetDelayed @@ Hold[fcn[file_Symbol, symbols], a]), 
               {RuleDelayed::"rhs"}]
    
    直到最近,它还具有

    fcn[ file_String, <otherparams> ] := OpenAndRead[file, fcn[#, <otherparams>]&]
    fcn[ file_InputStream, <otherparams> ] := <fcn body>
    
    哪个有用法

    MakeCheckedReader[ myReader, a_, b_ ] := {file$, a, b} (*as an example*)
    
    现在,检查
    myReader
    的定义会给出两个定义,就像我们想要的那样。但是,在函数体中,
    文件
    必须称为
    文件$
    。(我还没有想出如何按照我的意愿命名文件var。)

    Edit
    MakeCheckedReader
    本身不做任何事情。相反,
    TagSet
    ()规范告诉Mathematica,当在
    SetDelayed
    的LHS上找到
    MakeCheckedReader
    时,用所需的函数定义替换它。另外,请注意使用的
    Quiet
    ;否则,它会抱怨出现在等式右侧的模式
    a
    b

    编辑2:指出了在定义选中的读取器时如何能够使用
    文件
    而不是
    文件$
    。更新后的解决方案如下:

    OpenAndRead[file_String, fcn_]:=
    Module[{strm, res},
      strm = OpenRead[file];
      res = CheckAbort[ fcn[strm], $Aborted ];
      Close[strm];
      If[res === $Aborted, Abort[], res] (* Edited to allow Abort to propagate *)
    ]
    
    MakeCheckedReader /: 
        SetDelayed[MakeCheckedReader[fcn_Symbol, symbols___], a_] :=
        Quiet[(fcn[file_String, symbols] := OpenAndRead[file, fcn[#, symbols] &];
               SetDelayed @@ Hold[fcn[file_Symbol, symbols], a]), 
               {RuleDelayed::"rhs"}]
    
    他的这篇文章解释了这一变化的原因。如上所述定义
    myReader
    ,并检查其定义,我们得到

    myReader[file$_String,a_,b_]:=OpenAndRead[file$,myReader[#1,a_,b_]&]
    myReader[file_Symbol,a_,b_]:={file,a,b}
    

    我在晚会上迟到了,我有一个公认的答案和一个很好的回答
    f[...] := Module[... /; ...]
    
    data = {{0, 1}, {1, 2}, {2, 4}, {3, 8}, {4, 15}, {5, 29}, {6, 50}, {7,
         88}, {8, 130}, {9, 157}, {10, 180}, {11, 191}, {12, 196}, {13, 
        199}, {14, 200}};
    
    f0[x_] := First @ Cases[data, {t_, p_} /; p >= x :> t, {1}, 1]
    
    f0[100] (* returns 8 *)
    
    f0[1000]
    error: First::first: {} has a length of zero and no first element.
    
    f1[x_] := Cases[data, {t_, p_} /; p >= x :> t, {1}, 1]
    
    f1[100] (* returns {8} *)
    f1[1000] (* returns {} *)
    
    f2[x_] :=
      Module[{m},
        m = Cases[data, {t_, p_} /; p >= x :> t, {1}, 1];
        First[m] /; m =!= {}
      ]
    
    f2[100] (* returns 8 *)
    f2[1000] (* returns f2[1000] *)
    
    f2[x_] := Null /; Message[f2::err, x] 
    f2::err = "Could not find a value for ``.";
    
    f2[x_] := (Message[f2::err, x]; Abort[])
    
    Clear[f]
    f[x_] := ...
    f[x_] := Module[... /; ...]
    f[x_] := ... /; ...