Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template haskell ede #7

Merged
merged 9 commits into from
Sep 26, 2016

Conversation

cdepillabout
Copy link
Contributor

I have a rough version of #6 working.

It's currently not type-safe with respect to template parameters, but it does make sure the template parses correctly at compile time.

I don't think it's possible to take the template parameters from the environment, because it's impossible to see what variables nd types the template will need.

(For instance, with a template like {% if var %} {{ foo }} {% else %} {{ bar }} {% endif %}, it's impossible to know whether the template will need foo or bar without first trying to render it.)

Maybe if we used a different template library we could get something that is more type-safe.

Also, #6 needs to be merged in before this can be merged in.

@arowM Please take a look at this, especially commit c822470. What do you think?

@arowM
Copy link
Contributor

arowM commented Sep 19, 2016

I don't think it's possible to take the template parameters from the environment, because it's impossible to see what variables nd types the template will need.

Could you tell me a bit more about it?
I understand that EDE wraps variables with Data.Aeson.Value, so I guess we can use favorite type of environment variable.

Let me confirm the meaning of "type-safe on template parameter".
Generally, the template engine has following three steps.

  1. Load template file or embedded template text
  2. Compile the template
  3. Render the template with template parameters

Is it correct that you say it's better to check if all the embedded template variables are given and their types are correct on second step?

I surveyed some template engines and find that haiji package may match for our use.
After the survey, I propose we have following two choices.

a. No type checking on template parameters is not so serious for early stage of development, so enhance it later phase of development
b. Use haiji if the demerits are not so important

What do you think about demerits of haiji?

haiji

  • Can use raw html
  • Type check on compiling template

This is made by @notogawa.
Though this library matches for our use case, this package only support base < 4.9.
Hence we can't use the latest lts-7.0.

As well, this library have too many features for our use case.
It seems to cause extraordinary compilation time in some situation.

tpll

  • Can use raw html
  • NO type check on compiling template

In addition, the github README says that

This project is only for learning purposes. Not intended to be a long-term project, neither maintained. But well, feel free to use or fork it for your needs. :)

blaze-html

  • Can NOT use raw html
  • Type check on compiling template

This library provides Haskell functions to represent html context as Haskell code inspite of parsing template string.

servant-ede

  • Can use raw html
  • NO type check on compiling template

Though the name is servant-ede, it seems not type-safe for template parameters.
Furthermore, it only focuses on servant and it seems to be hard to use with spock.

Mustache

  • Can use raw html
  • type check on compiling template

Shakespeare

  • Can NOT use raw html
  • type check on compiling template

HStringTemplate

  • Can use raw html
  • NO type check on compiling template

karver

  • Can use raw html
  • NO type check on compiling template

@cdepillabout
Copy link
Contributor Author

@arowM

Let me confirm the meaning of "type-safe on template parameter".
Generally, the template engine has following three steps.

Load template file or embedded template text
Compile the template
Render the template with template parameters

Is it correct that you say it's better to check if all the embedded template variables are given and their types are correct on second step?

Yes, this is correct. I think it is generally better to make sure the templates can be rendered correctly at compile time.

However, (I think?) you will write a lot of the template html code, so ideally we should use a library that you like using.

Would you rather write the template html files with haiji or ede?

I will checkout the source code for the haiji library.

@arowM
Copy link
Contributor

arowM commented Sep 24, 2016

@cdepillabout

The only point which template html style I want to write is that the style does not conflict with pug.
Furthermore, it doesn't bother me if it conflicts or not because I can escape the sequences on pug.

In our case, we're already using template engine pug on front-end.
After compiling the template file on front-end, back-end uses another template engine to embed variables determined on back-end process.

The main role of those template engines are as follows.

  • Role of first template engine (pug)
    • share the header file
    • make it easy to write html file
    • embed variables we determined on front-end (like dev env or prod env)
    • and more convenient features
  • Role of second template engine (ede or haiji?)
    • embed variables that back-end process only knows

It implies that we do not expect any convenient functions on the second template engine.
It's the reason why I do not mind the template style of the second one.
(And it's why I felt that haiji has too many features for our use case.)

Please choose the second template engine by the back-end side convenience.

@cdepillabout
Copy link
Contributor Author

Okay, that makes sense.

In that case, let's use haiji because it is more type safe. It's a little cumbersome to use because of the type-safety, but I'm going to try to make a simple wrapper.

@cdepillabout
Copy link
Contributor Author

cdepillabout commented Sep 26, 2016

@arowM After playing around with haiji a little bit, I've discovered a big problem.

haiji causes ghc to throw an OutOfMemory error when trying to compile a template with many (>10) variables. Using even 4 or 5 variables causes ghc to take 5 to 6 GB of memory. This hits swap on my machine, and compilation consequently goes very slowly.

For now, lets just use ede. I'll merge in this PR.

If I have some free time this week, I will play around with ghc to see if I can figure out why compiling haiji takes so much time and memory. There were some good talks at ICFP/CUFP this year about contributing to GHC, so it's a good opportunity to play around with it.

I came up with a convenient syntax for writing haiji dictionaries (using ghc-8's new TypeApplication extension), so hopefully we can use that if we switch to haiji.

@cdepillabout cdepillabout merged commit 0301773 into blueimpact:master Sep 26, 2016
@notogawa
Copy link

I released haiji-0.2.0.0 with the proposed syntax. In this version, a memory usage while compile time will be reduced.

@arowM
Copy link
Contributor

arowM commented Sep 27, 2016

Thanks for informing us, @notogawa !

@arowM arowM mentioned this pull request Oct 2, 2016
@cdepillabout
Copy link
Contributor Author

@notogawa Thanks for releasing haiji-0.2.0.0!

Unfortunately, compile times for templates with large numbers of variables seem to still be quite slow. Compiling the following code takes a little over a minute on my machine:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
module Main where

import Data.Default (def)
import Text.Haiji 
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.IO as LT

main :: IO ()
main = LT.putStr
    $ render $(haijiFile def "content3.tmpl") $
        toDict @"a_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"b_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"c_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"d_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"e_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"f_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"g_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"h_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"i_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"j_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"k_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"l_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"m_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"n_variable" ("Hello,World!" :: LT.Text) `merge`
        toDict @"o_variable" ("Hello,World!" :: LT.Text)

content3.tmpl is very simple:

{{ a_variable }}
{{ b_variable }}
{{ c_variable }}
{{ d_variable }}
{{ e_variable }}
{{ f_variable }}
{{ g_variable }}
{{ h_variable }}
{{ i_variable }}
{{ j_variable }}
{{ k_variable }}
{{ l_variable }}
{{ m_variable }}
{{ n_variable }}
{{ o_variable }}

Last week I didn't find any time to play around with GHC to figure out why the compilation time takes so long, but maybe I'll be able to take some time this week.

@notogawa
Copy link

notogawa commented Oct 3, 2016

stack passes ghc options -ddump-hi -ddump-to-file to dump human readable .hi file (.dump-hi) under .stack-work dir. A type-level calculation (like haiji doing) creates large dump files. This dumping takes a long time and wastes our lifetime. Without these options, compiling finishes very fast.

When ghc 7.8, .dump-hi file is small because .hi file is also small. Since ghc 7.10, .hi file has rich information (for optimization ?) and human readable dump become large.

@cdepillabout
Copy link
Contributor Author

@notogawa Thanks for the explanation!

I tried recompiling my example program from above without -ddump-hi -ddump-to-file. The compilation time dropped from around 1 minute to just 10 seconds.

However, I couldn't find an easy way to force stack to not use -ddump-hi -ddump-to-file. It looks like it might not be possible with the current way stack works.

@cdepillabout cdepillabout deleted the template-haskell-ede branch October 3, 2016 11:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants