21

Haskell 2010 是否保证在编译时连接字符串文字?

如果我有

"This is a " ++
"very long String that " ++
"spans several lines"

编译器是否将其视为

"This is a very long String that spans several lines"

如果可能的话,我希望我的源代码行少于 80 个字符,但我不想引入运行时效率低下的问题。

4

4 回答 4

19

Haskell 2010 是否保证在编译时连接字符串文字?

不。

运行时效率远远超出Haskell2010的范围。我们不想仅仅因为它们很慢而禁止实验性实现。

此外,在编译期间说出应该做什么会给解释器带来麻烦,例如拥抱。

最后,给实现者一些自由是有用的。也许在某些奇怪的情况下,不预先计算字符串实际上会更快?

Haskell 2010 仅在错误的上下文中讨论编译时间。(例如,类型错误保证是编译时的。)

于 2013-07-07T15:33:51.517 回答
19

Haskell 2010 保证它在表示上等同于合并的字符串,但没有说明它应该如何编译。ghc-core不过,使用该工具进行检查很容易。

-- Test.hs
main = putStrLn $ "Hello " ++ "world"

当我们跑步时ghc-core Test.hs

[1 of 1] Compiling Main             ( Test.hs, Test.o )

==================== Tidy Core ====================
Result size of Tidy Core = {terms: 19, types: 23, coercions: 9}

main2 :: [Char]
[GblId,
 Unf=Unf{Src=<vanilla>, TopLvl=True, Arity=0, Value=False,
         ConLike=False, WorkFree=False, Expandable=False,
         Guidance=IF_ARGS [] 60 0}]
main2 = unpackCString# "Hello world"

...

并看到该字符串已合并到 Core 中间语言中。


编辑:为了强调我对其他答案的同意,仅仅因为这个特定的程序有一个带有合并字符串的核心转储并不能保证编译器会对所有字符串都执行此操作。符合 Haskell 规范并不意味着事情是如何编译的。

于 2013-07-07T15:23:37.973 回答
16

使用间隙——反斜杠之间的一个或多个空白字符序列:

"This is a \
\very long String that \
\spans several lines"

零宽度等效项是\&,用于将数字转义符与数字字符分开:

"\123\&45" == "{45"
"\12345" == "〹"
于 2013-07-09T01:33:39.920 回答
4

我不这haskell保证。可能会有编译器喜欢ghc执行这种优化,但没有标准保留它。因此,在未来的版本中可能不会发生这种优化。

如果您真的想保证它在编译时完成,为什么不使用 Template Haskell。以下示例在 ghc 上进行了测试,但我认为您也可以使其在其他编译器上运行:

在模块文件中,您可以有这样的代码

module Concat where
import Language.Haskell.TH

(<++>) :: String -> String -> ExpQ
(<++>) x y = stringE (x ++ y)

然后在您需要实际执行编译时连接的文件中

{-# LANGUAGE TemplateHaskell #-}
import Concat

f = $("This is a very long string" <++>
      "which spans over several lines")

您甚至可以使用-ddump-splices在编译时生成的连接字符串来签入 ghc。

于 2013-07-07T15:43:33.853 回答