对于Hamlet模板机制,我知道模板是在编译时解析的,导致源代码包含对 blaze-html 组合器的调用(可能还有其他表达式,因为插值)。所以插值发生的点(子树)在编译时是已知的。
在运行时,我们需要计算插值(当然),并将其“插入”树中,即应用 html 组合器。他们都是?实际上,其中一些应用程序可以在编译时进行评估(那些下面没有插值的应用程序)。这会发生吗?
自从我编写代码以来已经有一段时间了,所以不要把它当作权威(就像 Daniel 提到的那样,这-ddump-simpl
是一个很好的选择)。但我不相信我们正在使用 blaze-html 组合子,只是数据类型。Hamlet 本身在编译时尽可能多地连接字符串,以避免在运行时产生这种成本。我知道当我上次进行基准测试时(这是几年前的事),优化确实得到了很好的回报。
可能不是:您所要求的听起来很像部分评估(不要与部分应用程序混淆),这有点像编译器性能雷区,因此经常被避免。但是您可以自己检查;使用-ddump-simpl
您喜欢的优化级别来查看 GHC 生成的核心。
正如迈克尔所说:“哈姆雷特本身在编译时尽可能多地连接字符串,以避免在运行时产生这种成本。”
对于书中的例子,
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 的语法树(最后一行 - 字符串包含一个结束标记和下一个开始标记)。
这个哈姆雷特功能应该更多地宣传!