Hamlet 模板的编译时间与 运行 时间成本

compile-time vs. run-time cost of Hamlet templates

对于 Hamlet 模板机制,据我所知,模板是在编译时解析的,导致源代码包含对 blaze-html 组合器的调用(以及可能的其他表达式,因为插值).所以发生插值的点(子树)在编译时是已知的。

在运行时,我们需要计算插值(当然), 和 "plug it" 在树中,即应用 html 组合器。 他们都?实际上,其中一些应用程序可以在编译时进行评估(那些在它们下面没有插值的应用程序)。这会发生吗?

可能不是:您所要求的听起来很像部分求值(不要与部分应用混淆),这有点像编译器性能雷区,因此通常会避免。但是你可以自己检查一下;使用 -ddump-simpl 和您首选的优化级别来查看 GHC 生成的核心。

我已经有一段时间没有编写代码了,所以不要将其视为权威(就像 Daniel 提到的,-ddump-simpl 在这里是一个很好的选择)。但我不相信我们使用的是 blaze-html 组合器,只是数据类型。 Hamlet 本身会在编译时尽可能多地连接字符串,以避免在运行时产生这种成本。我知道当我上次进行基准测试时(这是几年前授予的),优化确实得到了很好的回报。

正如迈克尔所说 "Hamlet itself concatenates strings as much as possible at compile time to avoid that cost at runtime."

对于书中的例子,

main = putStrLn $ renderHtml [shamlet|
<p>Hello, my name is #{name person} and I am #{show $ age person}.
<p>
    Let's do some funny stuff with my name: #
    <b>#{sort $ map toLower (name person)}
<p>Oh, and in 5 years I'll be #{show ((+) 5 (age person))} years old.
|]
  where
    person = Person "Michael" 26

-ddump-simpl 包含这个:

               (>>
                  @ Text.Blaze.Internal.MarkupM
                  Text.Blaze.Internal.$fMonadMarkupM
                  @ ()
                  @ ()
                  (id
                     @ (Text.Blaze.Internal.MarkupM ())
                     (. @ Data.Text.Internal.Text
                        @ Text.Blaze.Internal.Markup
                        @ String
                        Text.Blaze.Internal.preEscapedText
                        Data.Text.pack
                        (GHC.CString.unpackCString#
                           ".</p>\n\
                           \<p>Let's do some funny stuff with my name: <b>"#)))

确实,那不是 HTML 的语法树(最后一行 - 字符串包含一个结束标记和下一个开始标记)。

这个哈姆雷特特色应该多宣传一下!