Время компиляции и время выполнения шаблонов Hamlet
Для механизма шаблонов Гамлета я понимаю, что шаблон анализируется во время компиляции, в результате чего получается исходный код, содержащий вызовы комбинаторов blaze-html (и, возможно, других выражений из-за интерполяции). Таким образом, точки (поддеревья), где происходит интерполяция, известны во время компиляции.
Во время выполнения нам нужно вычислить интерполированное значение (конечно) и "вставить его" в дерево, то есть применить комбинаторы html. Все они? На самом деле некоторые из этих приложений могут быть оценены во время компиляции (те, у которых нет интерполяции под ними). Это происходит?
3 ответа
Прошло много времени с тех пор, как я работал над кодом, так что не воспринимайте это как авторский (как упоминал Даниэль, -ddump-simpl
хороший звонок здесь). Но я не верю, что мы используем комбинаторы blaze-html, просто тип данных. Сам Гамлет объединяет строки в максимально возможной степени во время компиляции, чтобы избежать этих затрат во время выполнения. Я знаю, что когда я последний раз тестировал (что было сделано много лет назад), оптимизация окупилась довольно хорошо.
Вероятно, нет: то, что вы просите, звучит очень похоже на частичную оценку (не путать с частичным применением), которая является чем-то вроде минного поля производительности компилятора, поэтому ее часто избегают. Но вы можете проверить сами; использование -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 (последняя строка - строка содержит закрывающий тег и следующий открывающий тег).
Эта функция Гамлета должна рекламироваться больше!