Metaprogramming in Haskell vs. Ocaml

Hi all, I would like to learn a little bit more about metaprogramming in Haskell. And I'm also wondering why metaprogramming is used much more in Ocaml than in Haskell. Camlp4 (Ocaml's metaprogramming facility) doesn't seem to much more powerful that Template Haskell. The former is celebrated in its community as a killer feature of the language and its use is encouraged by numerous accessible tutorials. The latter however is down-played and not as well documented. Seeing that the languages are parallel in many ways is there some reason for this? Is metaprogramming less useful in Haskell? Is it worth learning? thanks ... -deech

aditya.siram:
Hi all, I would like to learn a little bit more about metaprogramming in Haskell. And I'm also wondering why metaprogramming is used much more in Ocaml than in Haskell.
Camlp4 (Ocaml's metaprogramming facility) doesn't seem to much more powerful that Template Haskell. The former is celebrated in its community as a killer feature of the language and its use is encouraged by numerous accessible tutorials. The latter however is down-played and not as well documented.
Seeing that the languages are parallel in many ways is there some reason for this? Is metaprogramming less useful in Haskell? Is it worth learning?
Template Haskell is actually a fairly popular extension (around 5% of Hackage packages use some TH). And the addition of quasiquotation -- which allows custom syntax -- might make it more popular. I think we don't see as much metaprogramming because of other language features -- laziness, operator syntax, and type classes -- make a bunch of common designs work without needing metaprogramming. -- Don

Don Stewart wrote:
I think we don't see as much metaprogramming because of other language features -- laziness, operator syntax, and type classes -- make a bunch of common designs work without needing metaprogramming.
While true, there are also 2 other reasons for meta-programmers are not all over Haskell: 1. efficiency nuts are already using C++ templates and don't see why they would switch, 2. people who care about types use a typed meta-language (like metaocaml) instead of an untyped template layer atop a (fantastic!) typed language. Actually, people in the #2 camp (like me) are keeping a close eye on dependently-typed languages (like Idris [1]) where partial evaluation has been show to be particularly easy and effective. I am eagerly (!) awaiting similar results from the Agda [2] camp. I believe the world really is ready for a typed metaprogramming language. I know I am. And I would really like it if Haskell were that language. Jacques [1] http://www.cs.st-andrews.ac.uk/~eb/Idris/ [2] http://wiki.portal.chalmers.se/agda/

On Mon, Apr 5, 2010 at 12:27 PM, Jacques Carette
Don Stewart wrote:
I think we don't see as much metaprogramming because of other language features -- laziness, operator syntax, and type classes -- make a bunch of common designs work without needing metaprogramming.
While true, there are also 2 other reasons for meta-programmers are not all over Haskell: 1. efficiency nuts are already using C++ templates and don't see why they would switch, 2. people who care about types use a typed meta-language (like metaocaml) instead of an untyped template layer atop a (fantastic!) typed language.
Are you implying that template haskell is not typed? Jason

On Mon, Apr 5, 2010 at 7:05 PM, Jason Dagit
On Mon, Apr 5, 2010 at 12:27 PM, Jacques Carette
wrote: 2. people who care about types use a typed meta-language (like metaocaml) instead of an untyped template layer atop a (fantastic!) typed language.
Are you implying that template haskell is not typed?
Not to speak for Jacques, but my impression is that while TH itself is typed--it's just more Haskell after all--it doesn't do much to prevent you from generating code that is not well-typed. Or even well-formed, for that matter; my initial attempts to learn how to use TH produced quite a few "that's impossible!" errors from GHC (I do not think that word means what it thinks it means). There's also type-level metaprogramming, as in e.g. HList, which is almost completely untyped. I have some personal library code that implements a simple meta-type system and it's a huge, horrid, painful mess for something with an expressive power no better than System F. In contrast, MetaOCaml seems to be some variety of a multi-stage system where metaprogramming blends smoothly into "regular" programming with a single, consistent type ensuring type safety at all points. - C.

Casey McCann wrote:
Not to speak for Jacques, :-)
and then you followed that up with a post with which I fully agree. Jacques
but my impression is that while TH itself is typed--it's just more Haskell after all--it doesn't do much to prevent you from generating code that is not well-typed. Or even well-formed, for that matter; my initial attempts to learn how to use TH produced quite a few "that's impossible!" errors from GHC (I do not think that word means what it thinks it means).
There's also type-level metaprogramming, as in e.g. HList, which is almost completely untyped. I have some personal library code that implements a simple meta-type system and it's a huge, horrid, painful mess for something with an expressive power no better than System F.
In contrast, MetaOCaml seems to be some variety of a multi-stage system where metaprogramming blends smoothly into "regular" programming with a single, consistent type ensuring type safety at all points.
- C.

Jason Dagit wrote:
While true, there are also 2 other reasons for meta-programmers are not all over Haskell: 1. efficiency nuts are already using C++ templates and don't see why they would switch, 2. people who care about types use a typed meta-language (like metaocaml) instead of an untyped template layer atop a (fantastic!) typed language.
Are you implying that template haskell is not typed?
Indeed. A template haskell meta-program is not typed at 'compile time' of the meta-program, but at 'run-time' of the splices. In other words, you can't typecheck a TH program without running it. You do get _some_ typing (because of the quotes have type Q Exp, Q [Dec] or Q Typ, but that is rather minimalistic. Compare with metaocaml where if you can compile you meta-program (i.e. code generator), then you are guaranteed that it can only ever produce valid, well-typed code. Not so with TH, where you can easily generate junk -- which GHC will promptly figure out and give you an error. But only 'late' in the process, which means that it can be fairly difficult to understand what the cause of the error really is. It's not nearly as bad as C++ templates, but it's well short of what metaocaml can do. Don't get me wrong - as a programming language, Haskell is still my favourite. It's just as a meta-programming language that it's not. [Unfortunately, I'm writing a lot of meta-programs these days !] Jacques

Jacques Carette wrote:
Jason Dagit wrote:
Are you implying that template haskell is not typed?
Indeed. [...]
Compare with metaocaml where if you can compile you meta-program (i.e. code generator), then you are guaranteed that it can only ever produce valid, well-typed code. Not so with TH, where you can easily generate junk -- which GHC will promptly figure out and give you an error.
I'm curious, can metaocaml create new data type definitions, value declarations or type class instances? I usually use TH to get rid of boilerplate that I cannot get rid off in Haskell itself, for instance for creating functional lenses for record types data Foo = Foo { bar_ :: Int, ...} $(DeriveLenses Foo) -- bar :: Lens Foo Int It seems to me that metaocaml is more used as "user annotated" partial evaluation? Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On Tue, 06 Apr 2010 15:08:45 +0200, Heinrich Apfelmus
Jacques Carette wrote:
Jason Dagit wrote:
Are you implying that template haskell is not typed?
Indeed. [...]
Compare with metaocaml where if you can compile you meta-program (i.e. code generator), then you are guaranteed that it can only ever produce valid, well-typed code. Not so with TH, where you can easily generate junk -- which GHC will promptly figure out and give you an error.
I'm curious, can metaocaml create new data type definitions, value declarations or type class instances? I usually use TH to get rid of boilerplate that I cannot get rid off in Haskell itself, for instance for creating functional lenses for record types
data Foo = Foo { bar_ :: Int, ...}
$(DeriveLenses Foo) -- bar :: Lens Foo Int
No metaocaml cannot do this. It is restricted to the expression level, and not the declaration level. Moreover you cannot pattern match over the generated code.
It seems to me that metaocaml is more used as "user annotated" partial evaluation?
That is a way to look at it. -- Nicolas Pouillard http://nicolaspouillard.fr

One thing I should have mentionned - TH and camlp4 are really equivalents. And camlp4 is as-typed-as TH (or not, depending on your point of view). I am co-author of a camlp4 extension, and I must admit that coding in camlp4 was not enjoyable, while coding in metaocaml (eventually) is. [I see that Nicolas Pouillard just answered the question about new type definitions, etc, as I was typing this answer] Heinrich Apfelmus wrote:
It seems to me that metaocaml is more used as "user annotated" partial evaluation?
I see most of my uses of metaocaml as code generation (building 'up' code from pieces by making explicit design choices) rather than classical partial evaluation (specializing code). Others would argue that these two activities are really the same thing -- and I would not really disagree! It's just that in my cases the 'specialization' is not driven by the partial evaluator at all, it is fully driven by the user [through explicit decisions of which modules/functors to use]. This requires a very different code organization, which is why I make the difference between the two approaches. The Haskell analogy: I write tons and tons of typeclass-level 'code', including typeclasses for type constructors (and type constructor transformers and ...) but then I ensure that whenever these are used, it can be statically determined exactly which instance should be used, and 100% of the dispatch overhead is eliminated AND I get full control over which methods get inlined in the final code. It is that 'full control' aspect which gets you reliable efficiency from highly abstract code. Jacques

On Tue, 06 Apr 2010 09:37:59 -0400, Jacques Carette
One thing I should have mentionned - TH and camlp4 are really equivalents. And camlp4 is as-typed-as TH (or not, depending on your point of view). I am co-author of a camlp4 extension, and I must admit that coding in camlp4 was not enjoyable, while coding in metaocaml (eventually) is.
This is not exactly the same, TH is a bit more typed than camlp4 here is two examples: {-# LANGUAGE TemplateHaskell #-} module Thtest1 (test) where test = [d| f :: Int f = True |] {-# LANGUAGE TemplateHaskell #-} module Thtest2 (test) where test = [e| 1 + x |] These two files are rejected at compile time before being spliced in. So there is a limited scope checking, and type checking (limited because manually using the AST constructors allow to workaround the typechecker). Second point, the Q monad allows to generate names in a rather safe way compared to camlp4. Third reification can be done on declarations done in other files. So that we can easily inspect the types and definitions of previous things, which a rather hard (near to impossible) in camlp4. Best regards, -- Nicolas Pouillard http://nicolaspouillard.fr

Nicolas Pouillard wrote:
Heinrich Apfelmus wrote:
I'm curious, can metaocaml create new data type definitions, value declarations or type class instances?
No metaocaml cannot do this. It is restricted to the expression level, and not the declaration level. Moreover you cannot pattern match over the generated code.
Jacques Carette wrote:
One thing I should have mentionned - TH and camlp4 are really equivalents. And camlp4 is as-typed-as TH (or not, depending on your point of view).
This is not exactly the same, TH is a bit more typed than camlp4 here is two examples:
Thanks for your clarifications, Jacques and Nicolas. :) Incidentally, the distinction between camlp4 and metaocaml makes me wonder whether it might be possible to implement the former *inside* the latter. In other words, maybe there exists a domain specific language inside camlp4 / TH that offers all the conveniences of metaocaml. Of course, this doesn't work right away because camlp4 / TH are compile-time only, but why not extend them slightly so that they can be used during run-time, too? Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

Hello aditya, Saturday, April 3, 2010, 6:56:23 AM, you wrote:
Haskell. And I'm also wondering why metaprogramming is used much more in Ocaml than in Haskell.
reasons are two-folded: haskell is more powerful language. in particular, there are lots of generic programming approaches besides TH. OTOH, TH is as powerful as any other syntax preprocessor, but not as easy to use. especially if you try to learn it by reading original papers i suggest you to postpone learning TH. it's not Haskell way :) -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com
participants (8)
-
aditya siram
-
Bulat Ziganshin
-
Casey McCann
-
Don Stewart
-
Heinrich Apfelmus
-
Jacques Carette
-
Jason Dagit
-
Nicolas Pouillard