我可以写{x,a,b} //做[...,#]而不是做[...,{x,a,b}]吗?

Nak*_*lon 8 coding-style wolfram-mathematica postfix-notation

我爱上了Ruby.在这种语言中,所有核心功能实际上都是方法 这就是为什么我更喜欢后缀表示法 - 当我想要处理的数据从匿名处理函数的主体中放置时,例如:array.map{...}.我相信,这个代码的易读性有很大优势.

但Mathetica,功能正常(是的,如果你想要它可以是程序性的)指示一个样式,其中函数名称放在数据的左边.正如我们在其手册中所看到的,//仅在它是一些简单的函数时使用,没有参数,如list // MatrixForm.当Function需要很多参数时,编写手册的人会使用语法F[data].
它会好起来的,但我的问题是这样的F[f,data],例如Do[function, {x, a, b}].大多数Mathematica函数(如果不是全部)都具有完全按此顺序的参数 - [function, data]而不是[data, function].由于我更喜欢​​使用纯函数来保持命名空间清理而不是在我的笔记本中创建很多命名函数,因此参数function可能太大 - 如此之大,该参数data将放在第5-20行代码之后函数调用.

这就是为什么有时候,当邪恶的 Ruby性质让我受到控制时,我用后缀方式重写这些函数:

做[f(x),{x,a,b}] \n {x,a,b} //做[f(x),#]&

因为它对我很重要,所以纯函数(可能是大代码)就是处理数据.是的我做到了,我很高兴.但有两件事:

  1. 这导致Mathematica突出显示解析器问题:x后缀表示法用蓝色突出显示,而不是绿松石;
  2. 每次当我查看Mathematica手册时,我都会看到这样的例子:Do[x[[i]] = (v[[i]] - U[[i, i + 1 ;; n]].x[[i + 1 ;; n]])/ U[[i, i]], {i, n, 1, -1}];这意味着......他们认为它很容易阅读/支持/等等.

所以这两件事让我在这里问这个问题:我是个坏男孩,使用我的Ruby风格,我应该像这些人一样编写代码,还是没关系,我不必担心,应该按我喜欢的方式写?

WRe*_*ach 10

你提出的风格经常是可能的,但在这种情况下是不可取的Do.问题是Do具有属性HoldAll.这很重要,因为循环变量(x在示例中)必须保持未评估状态并被视为局部变量.要查看此内容,请尝试评估这些表达式:

x = 123;

Do[Print[x], {x, 1, 2}]
(* prints 1 and 2 *)

{x, 1, 2} // Do[Print[x], #]&
(* error: Do::itraw: Raw object 123 cannot be used as an iterator.
   Do[Print[x], {123, 1, 2}]
*)
Run Code Online (Sandbox Code Playgroud)

发生错误是因为纯函数Do[Print[x], #]&缺少HoldAll属性,导致{x, 1, 2}被评估.您可以通过使用HoldAll属性显式定义纯函数来解决问题,因此:

{x, 1, 2} // Function[Null, Do[Print[x], #], HoldAll]
Run Code Online (Sandbox Code Playgroud)

...但我怀疑治愈比疾病更糟糕:)

因此,当一个正在使用的"结合"之类的表达式Do,Table,Module等等,这是最安全的与所述畜群一致.


Mr.*_*ard 8

我认为您需要学习使用Mathematica最自然支持的样式.当然,有不止一种方式,我的代码看起来不像其他人的.尽管如此,如果你继续尝试将Mathematica语法打造成你自己的先入为主的风格,基于不同的语言,我预见到会让你感到沮丧.

空白不是邪恶的,你可以轻松地添加换行符来分隔长参数:

Do[
  x[[i]] = (v[[i]] - U[[i, i + 1 ;; n]].x[[i + 1 ;; n]]) / U[[i, i]]
  , {i, n, 1, -1}
];
Run Code Online (Sandbox Code Playgroud)

这就是说,我喜欢使用我经常看到的更多前缀(f @ x)和infix(x ~ f ~ y)表示法编写,我觉得这很有价值,因为很容易确定这些函数分别接收一个和两个参数.这有点不标准,但我不认为它是在踢Mathematica语法的痕迹.相反,我认为使用语法有利.有时这会导致语法突出显示失败,但我可以忍受:

f[x] ~Do~ {x, 2, 5} 
Run Code Online (Sandbox Code Playgroud)

当使用除标准形式之外的任何东西f[x, y, z](根据需要使用换行符)时,您必须更加小心评估顺序,并且恕我直言,可读性会受到影响.考虑这个人为的例子:

{x, y} // # + 1 & @@ # &
Run Code Online (Sandbox Code Playgroud)

我觉得这不直观.是的,对于与Mathematica的操作顺序密切相关人来说,它是可读的,但我相信它并没有提高清晰度.我倾向于为//阅读是自然的命名函数保留postfix:

Do[f[x], {x, 10000}] //Timing //First
Run Code Online (Sandbox Code Playgroud)

  • +1,用于促进中缀形式,这通常有助于提高可读性. (2认同)

Leo*_*rin 7

我会说这是用一种语言B惯用语言尝试编程的最大错误之一A,只因为你碰巧很好地了解后者并喜欢它.借用习语没有错,但你必须确保足够好地理解第二语言,以便你知道为什么其他人会像他们那样使用它.

在你的例子的特定情况下,通常,我想提请注意其他人没有提到的一些事情.首先,Do是一个范围构造,它使用动态范围来本地化其迭代器符号.因此,你有:

In[4]:= 
x=1;
{x,1,5}//Do[f[x],#]&

During evaluation of In[4]:= Do::itraw: Raw object 
1 cannot be used as an iterator. >>

Out[5]= Do[f[x],{1,1,5}]
Run Code Online (Sandbox Code Playgroud)

真是一个惊喜,不是吗.当您Do以标准方式使用时,这不会发生.

其次,要注意的是,虽然这个事实很大程度上被忽视,f[#]&[arg]不是总是一样的f[arg].例:

ClearAll[f];
SetAttributes[f, HoldAll];
f[x_] := Print[Unevaluated[x]]

f[5^2]

5^2

f[#] &[5^2]

25
Run Code Online (Sandbox Code Playgroud)

这不会影响您的示例,但由于您操作范围,因此您的使用距离受此影响的情况非常接近.


rco*_*yer 6

Mathematica支持 4种方法将函数应用于其参数:

  1. 标准功能形式: f[x]
  2. 前缀:f@xg@@{x,y}
  3. 后缀:x // f,和
  4. 中缀:x~g~y相当于g[x,y].

您选择使用什么形式取决于您,并且通常是一种美学选择,而不是其他任何形式.在内部,f@x被解释为f[x].就个人而言,我主要使用postfix,就像你一样,因为我将链中的每个函数都视为转换,并且更容易将多个转换串联起来.也就是说,我的代码将充满标准形式和前缀形式,主要取决于奇思妙想,但我更倾向于使用标准形式,因为它唤起了关于函数参数的遏制感.

我花了一点自由的前缀形式,包括我的简写形式Apply(@@)旁边Prefix(@).在内置命令中,只有标准表单,中缀表单,并Apply允许您轻松地将多个变量传递给您的函数而无需额外的工作. Apply(例如g @@ {x,y})通过用函数替换Headexpression({x,y})来实现,实际上用多个变量(g@@{x,y} == g[x,y])来评估函数.

我用来使用postfix表单将多个变量传递给我的函数的方法是通过列表.这需要更多的工作,因为我必须写

{x,y} // f[ #[[1]], #[[2]] ]&
Run Code Online (Sandbox Code Playgroud)

指定哪个元素List对应于适当的参数.我倾向于这样做,但你可以将它与Apply喜欢结合起来

{x,y} // f @@ #&
Run Code Online (Sandbox Code Playgroud)

这涉及较少的打字,但是当您稍后阅读时可能更难以解释.

编辑:我要指出的是,fg上述仅仅是占位符,就可以了,而且往往是,用纯函数代替,如#+1& @ x大多是相当于#+1&[x],看到狮子座的回答.

为了澄清,每个狮子座的回答,之间的等价f@exprf[expr]如果是真的f不posses的属性会阻止表达expr,被传递到之前评估f.例如,所述的一个AttributesDoHoldAll,其允许它充当作用域构建体,其允许它的参数,以在内部评价而不撤消外界影响.该点将expr在传递之前进行评估f,因此如果您需要将其保持未评估状态,则必须格外小心,例如创建具有Holdstyle属性的纯函数.


acl*_*acl 5

正如你明显知道的那样,你当然可以做到.就个人而言,我不会担心手册如何编写代码,只是按照我发现自然和难忘的方式编写代码.

但是,我注意到我通常会陷入明确的模式.例如,如果我在计算后生成一个列表并偶然绘制它以确保它符合我的预期,我通常会这样做

prodListAfterLongComputation[
    args,
]//ListPlot[#,PlotRange->Full]&
Run Code Online (Sandbox Code Playgroud)

如果我有一个清单,比如说lst,我现在专注于制作一个复杂的情节,我会做的

ListPlot[
    lst,
    Option1->Setting1,
    Option2->Setting2
]
Run Code Online (Sandbox Code Playgroud)

所以基本上,任何偶然的,可能并不重要的可读性(我不需要能够即时解析第一个,ListPlot因为它不是那段代码的点)最终成为后缀,以避免破坏已经 -它应用于编写的复杂代码.相反,复杂的代码我倾向于以我以后最容易解析的方式编写,在我的例子中,这类似于

f[
    g[
        a,
        b,
        c
    ]
]
Run Code Online (Sandbox Code Playgroud)

即使它需要更多的输入,如果不使用Workbench/Eclipse插件,也会使重组代码变得更加有效.

所以我想我会回答你的问题,"在考虑到可读性的可能性以及可能的方便性损失之后做任何最方便的事情,例如代码突出显示,重构代码的额外工作等等".

当然,如果你是唯一一个使用某段代码的人,那么这一切都适用; 如果还有其他人,则完全是一个不同的问题.

但这只是一种意见.我怀疑任何人都可以提供更多.