Haskell在编译时是否连接了字符串文字?

时间:2013-07-07 15:01:42

标签: haskell concatenation string-literals

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

如果我有

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

编译器是否将其视为

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

如果可能的话,我想保持源行不超过80个字符,但我不想引入运行时效率低下。

4 个答案:

答案 0 :(得分: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规范并不意味着如何编译事物。

答案 1 :(得分:19)

  

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

没有

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

另外,说在编译期间应该做些什么会给解释者带来麻烦,例如Hugs。

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

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

答案 2 :(得分:16)

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

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

零宽度等效值为\&,对于将数字转义符与数字字符分开非常有用:

"\123\&45" == "{45"
"\12345" == "〹"

答案 3 :(得分: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是否在编译时生成了连接字符串。