2024年Clojure状态调查!中分享您的想法。

欢迎使用!请参阅关于页面以获取有关该功能更多信息。

+8
语法和读取器
编辑

问题

在Clojure代码中零零碎碎地包含了一些JavaScript、XML和HTML,这导致在处理引号时非常令人讨厌且容易出错。这种情况在脚本编写和运行Shell命令时也是如此,可能会遇到复杂的转义场景。

解决方案

添加一个可以适应包含任何类型字符串的字符串字面量,无需转义。

建议

文本块

某些其他语言提供了一种称为文本块的特性,其中可以使用三重或更多引号编写字符串,其中所有字符都允许使用。

(println """
         This " is allowed,
         and no need to escape it.
         """

文本块通常还带有其他附加功能,例如,字符串中不会包含第一行和最后一行的换行符。代码中三重引号的位置定义了字符串中行的开始。因此,上述代码打印

This " is allowed,
and no need to escape it.

而不是

         This " is allowed,
         and no need to escape it.

虽然文本块在视觉上很有吸引力,因为它们的源代码具有美好的对齐。但它们依赖于空格,而Clojure至今仍是一个不依赖空格的语言,这意味着空格并不重要。我认为最好保持这种状态。因此,下两个建议。

原始字符串

有时没有“块”功能的文本块被称为原始字符串字面量。

(println """This " is allowed,
and no need to escape it.
Also support multi-line, but
not the "block" style of text blocks.""")

因此

(println """
         This " is allowed,
         and no need to escape it.
         """

打印

         This " is allowed,
         and no need to escape it.

对于文本块不同。

如果需要三重引号,只需使分隔符为四重引号即可。

""""This """ is now allowed as well.""""

原始字符串的问题在于,如果您使用双引号作为分隔符

""This is a raw " string!""

但又想在开头或结尾处使用单引号

"""{{hello}}"""

我想得到的字符串是:"{{hello}}",而不是{{hello}},但是原始字符串无法区分这两种情况,因为它现在认为这是一个三重引号分隔符。

一个解决方案是允许在开头或结尾处使用转义的引号

""\"{{hello}}\"""

但不在中间

""\"{{he\llo}}\"""

这是字符串:"{{he\llo}}"

因此,转义字符\可以出现在除在跟随引号的开始以外的任何地方,在引号的结尾处如果跟随引号。

我还是找不到这个理想的方案。规则太多,还有一些情况下需要转义。

未转义的字符串(我最喜欢的)

这里的想法是允许任何字符串用作分隔符。因此,对于任何我们想要嵌入Clojure代码中的字符串,我们总能找到不在其内的字符串用作分隔符。

假设增加了 readline 宏 #text。该宏期望以下形式是一个普通字符串,用于告诉 readline 宏读取以下形式的分隔符。

(println #text "|" |"{{hello}}"|)

将会打印

"{{hello}}"

#text 的第一个参数告诉它下面的原始字符串的分隔符是什么。这样,你绝对不必在原始字符串中插入转义序列。对于任何给定的字符串,你可以找到一个不包含该字符串分隔符的字符串来正确处理它。

关于这种方法的一个疯狂的想法,只是随便说说,那就是如果你使用足够随机化的字符串作为分隔符,这可能是一种奇怪的注入攻击防护方法。

(println #text "xIBgdSl4TCCOIdqdMu9G" xIBgdSl4TCCOIdqdMu9G
Can't nobody guess the delimiter to escape the string context :p
xIBgdSl4TCCOIdqdMu9G)

谢谢

3 答案

+1
by

这已经被提出并拒绝了好几次,而且我认为这里没有新的论点。

by
嗯,我确实首先尝试搜索过。没有找到任何东西。我受到了有关Java JEP的启发:[https://openjdk.java.net/jeps/355](https://openjdk.java.net/jeps/355) 和 [https://openjdk.java.net/jeps/326](https://openjdk.java.net/jeps/326)
by
如果搜索“原始字符串”、“字符串字面量”、“heredoc”、“多行注释”等,就可以在Clojure和Clojure-dev的谷歌邮件组列表中找到许多讨论。

旧的设计页面:https://archive.clojure.org/design-wiki/display/design/Alternate%2Bstring%2Bquote%2Bsyntaxes.html

我想我应该把“decline”改写成“缺乏兴趣”;我认为Rich通常认为这类事情有很多微妙复杂的方面(尤其是对于工具),并且收益相对较低。
不使用三引号方法的一个论点是,这已经是合法的Clojure代码了

user=> (println """
这已经是有效的Clojure代码
""")
 
这已经是有效的Clojure代码
 
nil
user=>

(这并不表示你想的意思,但现在它是有效的,尽管我怀疑任何真正的代码都会这样做)
好吧,我承认我只在谷歌搜索过,没有特别搜索邮件列表:p。

我没有想到doc字符串也是一个用例,但这也确实是个好例子。

你提出的好点子,这种可能引入的工具复杂性。解析heredoc或类似的东西可能会更困难。

如果你看看Ruby、Perl和Python,你就会发现似乎没有人能就如何正确处理这个问题达成一致,这三种语言最终都支持多种方法。

说到对于工具来说不值得付出努力的问题。实际上,工具也可以解决这类问题。不是针对doc字符串的用例,而是针对我的代码片段。我知道在IntelliJ中,有一个模式会为你打开一个缓冲区,让你自由地输入,它会自动将你在字符串中输入的内容Java转义。也许我会在Emacs上做一些类似的事情。
@sean 好的抓取。无论是什么解决方案,我都会倾向于让它使用读取器标签。所以 #s """ """ 或者类似的。这样可以解决这个问题。
仅仅指出,Java 15 也引入了这个特性(我知道这是一个仅限于编译器的特性,所以 Clojure 的实现与此无关),但也许解决方案空间已经略微扩大。

仅仅指出,“原始字符串”,即需要较少引号的字符串,与读取宏一起,可以实现很多当前令人烦恼但无人问津的酷炫功能。
+1

从现状的积极方面来看,-- 将 XML 和 HTML 视为文本,长期以来让非 Clojurists 遭遇了可怕的麻烦,包括输出格式错误、注入、蹩脚的转换,以及难以评估正确性的代码!

Clojure 的一些良好声誉归功于基于数据(而非字符串)的约定。 "Hiccup" 和 "clojure.xml" 约定在 HTML 和 XML 方面证明非常有效,并且(在我的非量化经验中)在运行时出奇地便宜,这让它们在避免在代码中种植代码块方面产生了奇妙的好处。如果您 确实 有代码块,您可以在最早的时机使用 Enlive 等 parse 它们,并以数据结构的形式完成处理。

哦,JavaScript 可能有点牵强。最好是获取资源?如果使用 ClojureScript 编码,您可以使用宏在编译时从与 cljs 文件相同的类路径中获取资源。

总的来说,我认为 Clojure 不需要嵌入和调整代码中的 HTML 和 XML 字面量是一种明智的做法(我们为此感到幸运)。起初这可能会被认为是缺失的功能,但它的缺失对 Clojure 代码的可靠性来说是一种福利。

是一个很好的观点。对于 HTML 和 XML,我也同意。我的动力来自于做服务器端渲染,并在 Hiccup 中嵌入一些 JavaScript。

我实际上曾想过 CLJS 是否可以以这种方式嵌入,但我觉得不行。尽管如此,如果它真的可以,那将非常棒。
+1
by
重提 by

你好,

我认为也应该支持在Clojure中添加这个功能。一个漂亮的应用场景是支持样式组件,比如 https://styled-components.npmjs.net.cn/

const Button = styled.a`
  /* This renders the buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;

  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${props => props.primary && css`
    background: white;
    color: palevioletred;
  `}
`

上述代码的主要优势在于大部分是纯CSS,无需转换为Clojure。

在Clojure中添加原始字符串/块文本是否有问题?是的。
让我们围绕这个问题进行讨论,看看我们能走多远。

是否有可能以类似目前Java JEP的开发方式来实验Clojure的特性——有预览版本来探索和改进,直到它最终确定并添加到核心? https://openjdk.java.net/jeps/326

我对Clojure相当陌生,并且不太熟悉语言及其历史传统。我喜欢挑战传统,因为世界正在发生变化。那些曾经使我们的做事方式有意义的原因可能现在不再成立。

by
Clojure没有类似于Java JEP的流程。如果Rich Hickey对某个功能不感兴趣,那么他就不会将其作为Clojure官方版本的官方功能。

世界上任何人都可以创建自己的Clojure源代码的本地更改,并使用它,如果他们愿意的话。我听说有一些组织运行专为自身使用的Clojure的修补版本。

将此功能添加到您的Clojure本地副本非常简单。但这并不帮助在分布式Clojure程序中使用此功能,因为没有使用Clojure官方版本的人将能够编译和运行使用新功能的源代码。
by
我也想在Clojure中得到文本块。
我的用途是在Clojure中嵌入像Python这样的其他编程语言。

如果文本块是一种需求,否则引用问题会非常烦人。
...