代码之家  ›  专栏  ›  技术社区  ›  Yaroslav Bulatov

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

  •  13
  • Yaroslav Bulatov  · 技术社区  · 15 年前

    我遇到的一个典型情况是,当笔记本超过几个函数时——我评估一个表达式,但我得到的不是正确的答案。 哔哔声 接着是几十个无用的警告,接着是“进一步输出……将被抑制”

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

    Assert[expr_, msg_] := If[Not[expr], Print[msg]; Abort[], None]
    

    编辑11/14 警告雪崩的一般原因是当子表达式的计算结果为“bad”值时。这会导致父表达式的计算结果为“bad”值,而此“badness”会一直传播到根。一路上评估的内置组件会注意到坏处并发出警告。”“bad”可能是指一个有错误的头的表达式、元素数量错误的列表、负定矩阵而不是正定矩阵等。一般来说,它与父表达式的语义不符。

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

    将调试器设置为“在消息上中断”,可以防止错误的雪崩,尽管始终打开它似乎是一种过度杀伤力。

    5 回复  |  直到 10 年前
        1
  •  10
  •   Community Mohan Dere    9 年前

    Samsdram : Pattern x:{{_, _} ..} PatternTest ? Condition /; f[x_?(Head[#]===List&)] f[x_List]

    Off Quiet

    Throw Catch Message Check CheckAbort AbortProtect

    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 *)
    ]
    

    fcn[ file_String, <otherparams> ] := OpenAndRead[file, fcn[#, <otherparams>]&]
    fcn[ file_InputStream, <otherparams> ] := <fcn body>
    

    belisarius

    MakeCheckedReader /: 
        SetDelayed[MakeCheckedReader[fcn_Symbol, symbols___], a_] :=
        Quiet[(fcn[file_String, symbols] := OpenAndRead[file, fcn[#, symbols] &];
               fcn[file_Symbol, symbols] := a), {RuleDelayed::"rhs"}]
    

    MakeCheckedReader[ myReader, a_, b_ ] := {file$, a, b} (*as an example*)
    

    myReader file file$

    MakeCheckedReader TagSet /: SetDelayed a_ b_

    Leonid

    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"}]
    

    answer

    myReader[file$_String,a_,b_]:=OpenAndRead[file$,myReader[#1,a_,b_]&]
    myReader[file_Symbol,a_,b_]:={file,a,b}
    
        2
  •  8
  •   Community Mohan Dere    9 年前

    f[...] := Module[... /; ...]
    

    another SO question

    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_] := ... /; ...
    
        3
  •  3
  •   Samsdram    15 年前

    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
    
        4
  •  3
  •   Joshua Martell    15 年前

    f[x_?NumericQ] := x^2;
    f[args___] := Throw[{"Bad Arguments: ", Hold[f[args]]}]
    

    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]]}]]
    
        5
  •  3
  •   Dr. belisarius    15 年前

    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] 
    

    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]
    

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

    满足我的前提。

    编辑

    也许为函数添加“裸”定义也很方便,因为它不需要进行错误检查。我们可以将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[]]