XSLT是一种函数式编程语言吗?

24

关于函数式编程语言的几个问题让我思考XSLT是否是一种函数式编程语言。如果不是,它缺少哪些特性?XSLT 2.0 缩短或弥合了这种差距吗?


2
Eric,你会感兴趣的是XSLT 3.0确实是一种真正的函数式编程语言。它使用XPath 3.0,在其中函数是一等对象,可以作为参数传递给其他函数或作为调用函数的结果返回。 - Dimitre Novatchev
我看到你在Pluralsight上出色的XML课程。 - Alex Gordon
6个回答

31

XSLT是声明性的,与有状态的相对。

虽然XSLT基于函数式编程思想,但它不是完整的函数式编程语言,它缺乏将函数视为一等数据类型的能力。它有像惰性求值这样的元素来减少不必要的求值,还有显式循环的缺失。

尽管像函数式语言一样,我认为它可以通过自动安全多线程跨多个处理器进行良好的并行化。

来自XSLT的维基百科

作为一种语言,XSLT受到函数式语言和基于文本模式匹配的语言(如SNOBOL和awk)的影响。它最直接的前身是DSSSL,一种为SGML执行与XSLT为XML执行相同功能的语言。 XSLT也可以被视为模板处理器。

这是一个关于使用XSLT作为函数式语言的伟大网站,借助FXSL的帮助。 FXSL是一个实现支持高阶函数的库。

由于FXSL的存在,我认为XSLT没有必要成为完全的函数式语言。也许FXSL将来会作为W3C标准包含在内,但我没有证据。


@recursive:这些并不是命令式循环。执行顺序不能保证(这样可以更容易地进行并行实现)。我认为一个近似的类比是,使用 xsl:for-each 时,你在一个集合上创建了一个 _投影_。 - Abel
@Abel:输出的顺序似乎是有保证的,我没有看到实际执行顺序和最终结果顺序之间有什么有用的区别。这似乎是一个实现细节。 - recursive
@recursive 递归,正因为如此,这些循环与命令式语言中的循环不同。假设你有一个 xsl:message,它创建了一个副作用,无法保证它被调用的频率和顺序(虽然有方法可以强制执行)。因此,这不仅是一个实现细节,但这非常符合函数式编程的特性。 - Abel
你提供的链接是一个404错误页面 :C - Ky -

7

6
那就像我在编程时的感觉一样。XSLT完全基于定义函数并将其应用于选定的事件,这些事件沿着输入流传递。XSLT允许你设置变量。函数式编程不允许函数具有副作用-这是一个重要的限制。尽管如此,在XSLT中编写代码,你会有与函数式编程相同的感觉。你正在处理输入 - 你没有改变它 - 以创建输出。这是与使用DOM API时非常不同的编程模型。DOM根本没有分离输入和输出。你被交给了一个数据结构 - 你可以自由地修改它 - 没有犹豫、限制或懊悔。可以说,如果你喜欢函数式编程及其原则,你可能会感到很舒适。就像对事件驱动编程和XML本身的经验一样,也会让你对它感到舒适。如果你唯一的经验是自顶向下、非事件驱动程序,那么XSLT将是一个非常陌生的、外来的领域。至少在开始时是这样的。稍微积累一些经验,当XPath表达式和事件处理真正熟悉时再回到XSLT将会带来丰厚的回报。

1
是的,XSL 允许你设置一个变量,但它是不可变的。 - Camilo Martin
你说得对!我在那一点上错了。感谢你指出来。一旦你在XSLT中设置了变量值,就不能更改它。我曾经因为忘记或忽视这一点而遇到了一些问题。 - JohnnySoftware
你知道吗,我认为他们应该在语言本身中更明确地表达这一点,因为我相信你和我不是唯一一个陷入其中的人。<variable> 让我想到一些会变化的东西(在运行时)- <constant> 更准确。事实上,我记得我的 XSLT 经验尤其尴尬,特别是因为我期望它以一种它实际上并没有被设计用来表现的方式来运作,这与 Java 程序员第一次使用 Javascript 的感觉非常相似。 - Camilo Martin
@Abel,四年多过去了,但我仍然觉得XSLT令人费解。这就像有人设计了一艘宇宙飞船来修剪草坪。 - Camilo Martin
@camilo,通常情况下,有一个好的教练或互动课程,学习基础知识需要半天时间,但如果没有它,由于语法不同寻常,试错方法可能会导致很多挫败感。我不确定“飞船”类比是否正确,我认为相反,XSLT 1.0非常有限,XSLT 2.0有了很大改进,XSLT 3.0(带有XPath 3.1)使其成为一种成熟的语言。在XSLT中曾经困难的现在变得轻松愉快,表达式和结构更加清晰。 - Abel
显示剩余2条评论

5

大多数情况下,使XSLT不成为100%功能性编程语言的原因是其无法将函数视为一级数据类型。

可能还有其他原因,但这是显而易见的答案。

祝好运!


4
Saxon-SA引入了一些扩展函数,使XSLT功能更强大。您可以使用saxon:function()创建一个函数值(实际上是{http://net.sf.saxon/java-type}net.sf.saxon.expr.UserFunctionCall值),然后使用saxon:call()调用它。
Saxon-B也有类似的功能,配对使用saxon:expression()saxon:eval()。不同之处在于,saxon:expression()接受任何XPath表达式,并且saxon:eval()对其进行评估,而saxon:function()则接受一个函数名称,saxon:call()调用该函数。

就我所知,这在.NET中也是可能的,同样可以通过扩展实现,但在我看来并不如优雅。 - annakata
1
在XSLT中进行函数式编程不需要任何扩展,Jeni对此非常了解:http://fxsl.sf.net。FXSL是XSLT的函数式编程库,已经存在超过8年时间。它完全使用XSLT编写,几乎完整地实现了Haskell Prelude函数。 - Dimitre Novatchev
在带有XPath 3.0或3.1的XSLT 3.0中,函数现在是一等公民,可以作为项目传递或调用等。不再需要扩展。 - Abel

1

这并不是一个真正的争论,因为你只能声明变量,而不能在声明后更改它们的值。从这个意义上说,它是声明式而不是命令式风格,正如Novatchev先生在他的文章中所述。

像Scheme或Erlang这样的函数式编程语言也可以声明变量,在Haskell中你也可以这样做:

-- 函数'test'接受变量x并将其添加到列表xs的每个元素上

test :: [Int] -> [Int]
test xs = map (+ x) xs
where x = 2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接