Template Haskell a Permanent solution?

Cafe, First let me say that Template Haskell is very powerful and a lot of great work has been done in this area. It fills in a number of holes in Haskell's feature set. But TH gives me the same feeling as other language features that have been described as "bolted on." Also, TH is both library and built-in syntax (via an extension) which feels strange to me. Finally, It's very complicated to do some simple things. I see TH used most for the following tasks: #1 Parse a string at compile-time so that a custom syntax for representing data can be used. At the extreme, this "data" might even be an EDSL. #2 Provide instances automatically. I would propose that more specialized features be implemented to accomplish these tasks. To start, I'll throw out some ideas that provide these capabilities. For TH use #1, compile-time parsing of arbitrary strings, I think it would be nice for quasiquote semantics to be modified so that code like
json :: String -> JsonObject json = ...
data = [ json | { "name" : "Jonathan" , "favorite language": "Haskell" } |]
causes the function json to be called at compile time with a string argument of " {\"name\" : \"Jonathan\"\n , \"favorite language\": \"Haskell\"\n }". The whole expression being then replaced with the result of the function application. What I like about this is that defining "quasiquoters" is trivial. They're just functions of the form String -> a. Many such quasiquoters already exist and would be ready for use! I imagine certain rules would apply, ie a quasiquoter must be defined prior to use and in a separate module, etc. For TH use #2, automatic instances, I would propose a way of declaring that a class can be automatically derived, and therefore added to the set [Eq, Ord, Show, Read, ... , etc]. This is the set of classes that can be put in the "deriving" clause of a type declaration. I don't know exactly what the syntax for this would look like, but I imagine it would look a bit like the various current implementations of automatic instances in TH. Again, TH is very powerful, and fills in a number of holes in Haskell's feature set. But it leaves me wondering if these holes should not be filled in by other, more specialized features, leaving TH to continue to find other holes to fill. I'm wondering if others see TH as a permanent solution, or if you agree with me that some of TH's most common usages should have more specialized features dedicated to them. It may very well be that I am simply not experienced enough with TH to fully appreciate and embrace it. By the way, did I miss any uses of TH as common as the ones I mentioned? --Jonathan

On Mon, 27 Dec 2010, Jonathan Geddes wrote:
#1 Parse a string at compile-time so that a custom syntax for representing data can be used. At the extreme, this "data" might even be an EDSL.
I think it would be enough, if the compiler could be told to unfold an expression like parse "text in a domain specific language" at compile time.
#2 Provide instances automatically.
http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/generic-classes.... I also think that Template Haskell is used too much. Several things that are done in existing libraries could be done in plain Haskell in a better way. For the cases where Template Haskell is really needed, I'd prefer a solution that allows to generate the code before compilation, such that packages with automatically generated code can be run also on compilers that do not support Template Haskell.

Hi Henning,
I also think that Template Haskell is used too much. Several things that are done in existing libraries could be done in plain Haskell in a better way.
Can you give any examples of this? I'm not saying it's not true, I'm just
curious as to why you would venture into the realm of TH without a reason.
/J
On 27 December 2010 08:44, Henning Thielemann wrote: On Mon, 27 Dec 2010, Jonathan Geddes wrote: #1 Parse a string at compile-time so that a custom syntax for representing data can be used. At the extreme, this "data" might even
be an EDSL. I think it would be enough, if the compiler could be told to unfold an
expression like
parse "text in a domain specific language"
at compile time. #2 Provide instances automatically. http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/generic-classes.... I also think that Template Haskell is used too much. Several things that
are done in existing libraries could be done in plain Haskell in a better
way. For the cases where Template Haskell is really needed, I'd prefer a
solution that allows to generate the code before compilation, such that
packages with automatically generated code can be run also on compilers that
do not support Template Haskell. _______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

On Mon, 27 Dec 2010, Jonas Almström Duregård wrote:
Hi Henning,
I also think that Template Haskell is used too much. Several things that are done in existing libraries could be done in plain Haskell in a better way.
Can you give any examples of this? I'm not saying it's not true, I'm just curious as to why you would venture into the realm of TH without a reason.
E.g. refer to the recent discussion of storable-endian. http://www.haskell.org/pipermail/haskell-cafe/2010-December/087551.html Or look into package 'encoding'. It uses TemplateHaskell in order to convert Text descriptions of character sets into Haskell tables. I think the character tables could be simply rewritten to Haskell syntax, or they could be parsed by a function, where the parsed content is unfolded at compile time. It could even be computed at runtime, since it is only computed once because of laziness.

2010/12/27 Henning Thielemann
Or look into package 'encoding'. It uses TemplateHaskell in order to convert Text descriptions of character sets into Haskell tables. I think the character tables could be simply rewritten to Haskell syntax, or they could be parsed by a function, where the parsed content is unfolded at compile time. It could even be computed at runtime, since it is only computed once because of laziness.
http://hackage.haskell.org/package/zeroth ? -- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com IvanMiljenovic.wordpress.com

On Mon, Dec 27, 2010 at 12:44 AM, Henning Thielemann
I think it would be enough, if the compiler could be told to unfold an expression like parse "text in a domain specific language" at compile time.
I'm afraid I have to disagree with you here. Being able to specify that the string should be parsed at compile time is only half of the equation in my mind. The other half is the clean syntax for multi-line strings. Haskell already has great syntax for specifying data in a declarative manner. Especially in contrast with ie Java/C++. Even as good as the dynamic languages ie JavaScript/Python/Ruby. When you add the ability to specify data in ANY syntax you can parse, Haskell is clearly the best. But the complexity of TH detracts from the elegance of this greatly in my opinion. And wrapping your "data" in string syntax, multi-line or otherwise, detracts from the elegance as well. A syntax has to be less painful or more convenient or more readable/maintainable than literal list/record syntax before it is useful.

Am 27.12.2010 08:44, schrieb Henning Thielemann:
On Mon, 27 Dec 2010, Jonathan Geddes wrote:
#1 Parse a string at compile-time so that a custom syntax for representing data can be used. At the extreme, this "data" might even be an EDSL.
I think it would be enough, if the compiler could be told to unfold an expression like parse "text in a domain specific language" at compile time.
#2 Provide instances automatically.
http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/generic-classes....
I see the text below and have no idea where the package lang or the module Generic comes from. Can someone enlighten me? I didn't find package lang on hackage. Cheers Christian 7.16.1. Using generics To use generics you need to * Use the flags -fglasgow-exts (to enable the extra syntax), -XGenerics (to generate extra per-data-type code), and -package lang (to make the Generics library available. * Import the module Generics from the lang package. This import brings into scope the data types Unit, :*:, and :+:. (You don't need this import if you don't mention these types explicitly; for example, if you are simply giving instance declarations.)

Christian Maeder schrieb:
Am 27.12.2010 08:44, schrieb Henning Thielemann:
On Mon, 27 Dec 2010, Jonathan Geddes wrote:
#2 Provide instances automatically. http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/generic-classes....
I see the text below and have no idea where the package lang or the module Generic comes from. Can someone enlighten me?
The package 'syb' - 'scrap your boilerplate' looks quite similar.

Am 04.01.2011 15:48, schrieb Henning Thielemann:
Christian Maeder schrieb:
Am 27.12.2010 08:44, schrieb Henning Thielemann:
On Mon, 27 Dec 2010, Jonathan Geddes wrote:
#2 Provide instances automatically. http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/generic-classes....
I see the text below and have no idea where the package lang or the module Generic comes from. Can someone enlighten me?
The package 'syb' - 'scrap your boilerplate' looks quite similar.
Yes, thanks. So the documentation should be updated to say "package syb" and "module Data.Generics". @Ian, can you take care of this (without ticket)? Christian

On Tue, Jan 04, 2011 at 04:15:07PM +0100, Christian Maeder wrote:
Am 04.01.2011 15:48, schrieb Henning Thielemann:
Christian Maeder schrieb:
Am 27.12.2010 08:44, schrieb Henning Thielemann:
On Mon, 27 Dec 2010, Jonathan Geddes wrote:
#2 Provide instances automatically. http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/generic-classes....
I see the text below and have no idea where the package lang or the module Generic comes from. Can someone enlighten me?
The package 'syb' - 'scrap your boilerplate' looks quite similar.
Yes, thanks. So the documentation should be updated to say "package syb" and "module Data.Generics".
@Ian, can you take care of this (without ticket)?
Done, ta. Thanks Ian

On 27 December 2010 07:35, Jonathan Geddes
#1 Parse a string at compile-time so that a custom syntax for representing data can be used. At the extreme, this "data" might even be an EDSL.
Hello Jonathan By this are you meaning to add quasiquoting to the language "Haskell" or the "Glasgow Haskell", taking it out of the domain of Template Haskell? How would the first example look like with Template Haskell and is current quasiquoting syntax? I'm suspecting the differences are pretty small.

On Mon, Dec 27, 2010 at 1:14 AM, Stephen Tetley
By this are you meaning to add quasiquoting to the language "Haskell" or the "Glasgow Haskell", taking it out of the domain of Template Haskell?
I believe that all new features should start as extensions and as an extension, these things could coexist with TH. I just can't see TH becoming standard. I think something much simpler that accomplishes the common uses of TH is more likely to make it into Haskell' 20[1-2]x. --Jonathan

Hi,
But TH gives me the same feeling as other language features that have been described as "bolted on." Also, TH is both library and built-in syntax (via an extension) which feels strange to me.
I don't understand why the library/extension duality is a problem. I would say that the best approach is to have language support (through extensions) for primitive operations like splicing, and to have libraries that combine these operations into more complex systems (like automatic derivation of type classes).
Again, TH is very powerful, and fills in a number of holes in Haskell's feature set. But it leaves me wondering if these holes should not be filled in by other, more specialized features, leaving TH to continue to find other holes to fill.
Shouldn't specialized features be defined in terms of general features?
json :: String -> JsonObject json = ...
data = [ json | { "name" : "Jonathan" , "favorite language": "Haskell" } |]
How does this differ from the current QuasiQuotes extension? From what I can
tell, all you need to achieve this with TH is to automatically derive a
Language.Haskell.TH.Lift instance for JsonObject, i.e. a function lift ::
JsonObject -> Q Exp such that the expression will evaluate to the original
JsonObject. A QuasiQuoter like the one you describe can then be created by
QuasiQuoter { parseExp = lift . json }. Should both approaches be supported
directly, or should we sacrifice the generality of the current quoters for
the simplicity of the ones you suggest?
The second part (deriving instances for general type classes) is a lot more
complicated. I would say that the most general way of showing that a class
can be derived is to provide a function that produces a set of declarations
given the name of the datatype. Here's a very simple suggestion for
incorporating this into the Haskell deriving syntax. Suppose we have these
two classes and TH functions for deriving them:
class Class1 ...
class Class2 ...
class1 :: Name -> Q [Dec]
class2 :: Name -> Q [Dec]
data D = D deriving (Show,class1,class2)
The last declaration could expand to:
data D = D deriving Show
class1 'D
class2 'D
If you don't want to write class1 and class2 by operating directly on
Haskell declarations, but rather use some DSL for specifying instances, then
all you need is a function deriv :: DerivationDSL -> (Name -> Q [Dec]).
/J
On 27 December 2010 08:35, Jonathan Geddes
Cafe,
First let me say that Template Haskell is very powerful and a lot of great work has been done in this area. It fills in a number of holes in Haskell's feature set.
But TH gives me the same feeling as other language features that have been described as "bolted on." Also, TH is both library and built-in syntax (via an extension) which feels strange to me. Finally, It's very complicated to do some simple things.
I see TH used most for the following tasks:
#1 Parse a string at compile-time so that a custom syntax for representing data can be used. At the extreme, this "data" might even be an EDSL. #2 Provide instances automatically.
I would propose that more specialized features be implemented to accomplish these tasks. To start, I'll throw out some ideas that provide these capabilities.
For TH use #1, compile-time parsing of arbitrary strings, I think it would be nice for quasiquote semantics to be modified so that code like
json :: String -> JsonObject json = ...
data = [ json | { "name" : "Jonathan" , "favorite language": "Haskell" } |]
causes the function json to be called at compile time with a string argument of " {\"name\" : \"Jonathan\"\n , \"favorite language\": \"Haskell\"\n }". The whole expression being then replaced with the result of the function application. What I like about this is that defining "quasiquoters" is trivial. They're just functions of the form String -> a. Many such quasiquoters already exist and would be ready for use! I imagine certain rules would apply, ie a quasiquoter must be defined prior to use and in a separate module, etc.
For TH use #2, automatic instances, I would propose a way of declaring that a class can be automatically derived, and therefore added to the set [Eq, Ord, Show, Read, ... , etc]. This is the set of classes that can be put in the "deriving" clause of a type declaration. I don't know exactly what the syntax for this would look like, but I imagine it would look a bit like the various current implementations of automatic instances in TH.
Again, TH is very powerful, and fills in a number of holes in Haskell's feature set. But it leaves me wondering if these holes should not be filled in by other, more specialized features, leaving TH to continue to find other holes to fill.
I'm wondering if others see TH as a permanent solution, or if you agree with me that some of TH's most common usages should have more specialized features dedicated to them. It may very well be that I am simply not experienced enough with TH to fully appreciate and embrace it.
By the way, did I miss any uses of TH as common as the ones I mentioned?
--Jonathan
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Thanks, everyone, for the responses.
I don't understand why the library/extension duality is a problem.
I don't think it is a _problem_ it just feels strange to me. Maybe I'm misunderstanding, is it possible to use TH without using the library components?
Shouldn't specialized features be defined in terms of general features?
Absolutely, but usually don't you use the specialized features over general ones where you can? For example, I don't often (if ever) use the general feature of the goto statement in C. Instead I use conditionals, loops, and functions. I don't often write explicitly recursive functions in Haskell, rather I use map, filter, fold, etc. whenever the structure of the recursion allows.
How does this differ from the current QuasiQuotes extension? From what I can tell, all you need to achieve this with TH is to automatically derive a Language.Haskell.TH.Lift instance for JsonObject, i.e. a function lift :: JsonObject -> Q Exp such that the expression will evaluate to the original JsonObject. A QuasiQuoter like the one you describe can then be created by QuasiQuoter { parseExp = lift . json }.
Right, it's not a lot of extra work. But it's enough that in most cases, I stick with constructing records or using other built-in syntax.
Should both approaches be supported directly, or should we sacrifice the generality of the current quoters for the simplicity of the ones you suggest?
No, I don't think TH should be sacrificed. I just think more specific (and more simple) features might be nice in place of some of TH's specific uses.

Hi, Jonathan Geddes wrote:
For TH use #1, compile-time parsing of arbitrary strings, I think it would be nice for quasiquote semantics to be modified so that code like
json :: String -> JsonObject json = ...
data = [ json | { "name" : "Jonathan" , "favorite language": "Haskell" } |]
causes the function json to be called at compile time with a string argument of " {\"name\" : \"Jonathan\"\n , \"favorite language\": \"Haskell\"\n }". The whole expression being then replaced with the result of the function application. What I like about this is that defining "quasiquoters" is trivial. They're just functions of the form String -> a. Many such quasiquoters already exist and would be ready for use! I imagine certain rules would apply, ie a quasiquoter must be defined prior to use and in a separate module, etc.
First note that this is just quotation, not yet quasiquotation. For quasiquotation, you would also need to support antiquotation (i.e., the use of Haskell identifiers or even expressions in the middle of quoted syntax). And to reach something similar to the current support for quasiquotation, you would need to support patterns etc., too. Secondly, I was going to propose to use generic programming to convert from a parser like (String -> JsonObject) to a quasiquoter for Json. But after half a day of experiments, I figured out that this idea is already developed in Geoffrey B. Mainland. Why It's Nice to be Quoted: Quasiquoting for Haskell. Haskell Workshop 2007 Available at: http://www.eecs.harvard.edu/~mainland/publications/mainland07quasiquoting.pd... In that paper, Geoffrey Mainland explains how a parser can be generically upgraded to a quoter, reaching an intermediate conclusion on page 6:
By using generic programming, we can take a parser and create expression and pattern quasiquoters for the language it parses with only four lines of code, including type signatures! This holds not just for our simple object language, but for any object language.
He goes on to explain how to add "support for antiquotation [...] with only slightly more than four lines of code". The functions dataToExpQ and dataToPatQ from that paper are available in the TH library in Language.Haskell.TH.Quote. A simple helper function quasiQuoter :: Data a => (String -> Either String a) -> QuasiQuoter quasiQuoter parser = QuasiQuoter { quoteExp = either fail (dataToExpQ (const Nothing)) . parse , quotePat = either fail (dataToPatQ (const Nothing)) . parse } should allow you to write your JSON example as follows: parse :: String -> Either String JsonObject parse = ... json = quasiQuoter parse This seems simple enough to me, so it looks as if your use case is already supported as a library on top of the more general API. Tillmann

On Tue, Dec 28, 2010 at 8:17 AM, Tillmann Rendel
This seems simple enough to me, so it looks as if your use case is already supported as a library on top of the more general API.
This is exactly what I was looking for, and much simpler than my previous experiences with quasiQuoters. In the original post I said, "It may very well be that I am simply not experienced enough with TH to fully appreciate and embrace it." More and more I am thinking this is the case. I'll have to give TH a more thorough look. BTW, in addition to the resources already given, can anyone suggest materials for my aforementioned "more thorough look?" Thanks again for the responses. --Jonathan

All,
2010/12/27 Jonathan Geddes
I see TH used most for the following tasks:
#1 Parse a string at compile-time so that a custom syntax for representing data can be used. At the extreme, this "data" might even be an EDSL. #2 Provide instances automatically.
Just a note that TH is also sometimes used in its generality: as a general compile time meta-programming facility. For example, in my experimental grammar-combinators parsing library [1], I am using it to perform grammar transformations at compile time by simply generating the definition for the transformed grammar using TH. This could be extended in the future to provide a low-cost parser generator that works from within TH, which can reuse the library's infrastructure. Dominique [1] http://projects.haskell.org/grammar-combinators/
participants (9)
-
Christian Maeder
-
Dominique Devriese
-
Henning Thielemann
-
Ian Lynagh
-
Ivan Lazar Miljenovic
-
Jonas Almström Duregård
-
Jonathan Geddes
-
Stephen Tetley
-
Tillmann Rendel