问题 Infix for All(叶子)


Infix[] 仅适用于第一级:

Infix[(c a^b)^d]
(*
-> (a^b c) ~Power~ d
*)

因为我想(不要问为什么)将完整的表达式切换为中缀符号,我尝试了类似的东西:

SetAttributes[toInfx, HoldAll];
toInfx[expr_] := Module[{prfx, infx},
  prfx = Level[expr, {0, Infinity}];
  infx = Infix /@ prfx /. {Infix[a_Symbol] -> a, Infix[a_?NumericQ] -> a};
  Fold[ReplaceAll[#1, #2] &, expr, Reverse@Thread[Rule[prfx, infx]]]
  ]
k = toInfx[(c a^b)^d]
(*
-> (c ~Times~ (a ~Power~ b)) ~Power~ d
*)

但这有两个明显的问题,因为

  1. (c a^b)^d == a~Power~b~Times~c~Power~d
    所以我得到的并不是有效使用中缀。
  2. 它不健壮,并且无法轻松表达,例如 k = toInfx[a/b + ArcTan[a/b]]

有一个简单的方法来获得 Infix[] 全民工作(离开)?


3308
2017-11-27 15:05


起源

+1试图自动开玩笑 - acl
你这个混蛋<grin> - Mr.Wizard
我完全可以看到这一点 非常 有用的:P - abcd
@acl那个不会死的笑话的故事...... - Sjoerd C. de Vries
由于这个问题不是我认为的那个笑话,我将补充一点,我对一个算法感兴趣,找到最小括号的中缀形式。 - Mr.Wizard


答案:


这是一种方式:

ClearAll[toInfixAlt];
SetAttributes[toInfixAlt, HoldAll];
toInfixAlt[expr_] :=
 First@MapAll[Infix, HoldForm[expr]] //. 
   Infix[a : _?(Function[s, AtomQ[Unevaluated@s], HoldAll]) | _[_]| _[]] :> a

我用了 HoldForm 因为您可能希望代码保持不被评估。这是一个例子:

In[781]:= toInfixAlt[(c a^b)^d/(1/2)]
Out[781]= ((c ~Times~ (a ~Power~ b)) ~Power~ d) ~Times~ (1/((1/2)))

编辑

和,

In[792]:= toInfixAlt[a/b+ArcTan[a/b]]
Out[792]= (a ~Times~ (b ~Power~ (-1))) ~Plus~ ArcTan[a ~Times~ (b ~Power~ (-1))]

结束编辑

至于多余的括号,删除它们比较困难,因为由于各种操作符的优先级,它们确实需要它们,但应该是可能的。

编辑2

为了优先考虑,这是一个尝试:

ClearAll[toInfixAlt];
SetAttributes[toInfixAlt, HoldAll];
toInfixAlt[expr_] := 
  First@MapAll[Infix, HoldForm[expr]] //. 
     Infix[a : _?(Function[s, AtomQ[Unevaluated@s],HoldAll]) | _[_] | _[]] :> a //. 
     {
        Infix[f_[a__, Infix[r : (h_[___])],b___]] /; 
            Precedence[Unevaluated[f]] <= Precedence[Unevaluated[h]] :> Infix[f[a, r, b]],
        Infix[b___,f_[Infix[r : (h_[___])], a__]] /; 
            Precedence[Unevaluated[f]] <= Precedence[Unevaluated[h]] :> Infix[f[b, r, a]]
     };

现在,我得到:

In[963]:= toInfixAlt[a/b+ArcTan[a/b]]
Out[963]= (a b ~Power~ (-1)) ~Plus~ ArcTan[a ~Times~ (1/b)]

6
2017-11-27 15:20



谢谢!似乎这也失败了 a/b + ArcTan[a/b]。我对吗? - Dr. belisarius
@belisarius我刚编辑包含那个案例(补充说 _[_] 到代码中的模式)。 - Leonid Shifrin
持有表达式中的某些东西似乎是错误的。尝试 toInfixAlt[Solve[x^5 + 2 x + 1 == 0, x]] - Dr. belisarius
Leonid,你的“解析器bug”实际上是一个我很有价值的功能,那就是~Infix~优先级都是一样的,所以你可以简单地从左到右阅读表达式,就像我从整个第一天开始说的那样家当。 - Mr.Wizard
@先生。你认为这个是一个模拟问题! :) - Dr. belisarius


这是我的方法,非常类似于列昂尼德的:

(* In[118]:= *) foo[a:_[_,__]]:=Infix[a]
                foo[a_]:=a

(* In[120]:= *) MapAll[foo,(c a^b)^d]

(* Out[120]= *) (c ~Times~ (a ~Power~ b)) ~Power~ d

(* In[121]:= *) MapAll[foo,a/b+ArcTan[a/b]]

(* Out[121]= *) ArcTan[a ~Times~ (b ~Power~ (-1))] ~Plus~ (a ~Times~ (b ~Power~ (-1)))

3
2017-11-27 15:50



+1请尝试 MapAll[foo, Solve[x^5 + 2 x + 1 == 0, x]] - Dr. belisarius
似乎无法正常工作 Solve[x^5 + 2 x + 1 == 0, x]。运用 Unevaluated@Solve[...] 有所帮助,但不完全。还有,比如 #1^2 + #2^2 & 是有问题的。 - Leonid Shifrin
@belisarius对不起,没看到你的评论。 - Leonid Shifrin


我不知道为什么我要帮你取笑我,但......

(c a^b)^d //. h_[a_, b_] :> ix[a, h, b] /. ix :> (Infix[{##}, "~"] &)

2
2017-11-27 15:25



我不是取笑你。你的小小的娱乐在这里引起了很多思考。我觉得更喜欢和你玩,并学习一点。 - Dr. belisarius
Infix也可以用于超过2个术语的表达式,比如 a+b+c 例如。您的代码不包括此内容。 - Leonid Shifrin
@belisarius没关系:-) Leonid,我真的没有认真对待这个问题。 - Mr.Wizard