Explanation of macros; Haskell macros
Tomasz Zielonka
t.zielonka at students.mimuw.edu.pl
Mon Oct 6 21:16:25 EDT 2003
mike420 at ziplip.com wrote:
> Someone pointed out that Haskell has macros. Does anyone
> know how they relate to Lisp and Scheme macros? Better, worse,
> different?
You can find a short comparison of Scheme and Template Haskell (TH) approach
in (pages 12-13):
http://www.haskell.org/th/papers/meta-haskell.ps
I would say that similarity between them is much bigger than between,
say, TH and C++ template meta-programming, or between Scheme and C++ tmp.
> If anyone knows them well, can you show how you would do "for i in
> ...." using Haskell macros?
Haskell macros/templates provide mechanisms for introspection. They
allow you to process Haskell abstract syntax trees as values of
algebraic datatype Exp. That's probably a little more complicated than
in LISP and Scheme, because Haskell's syntax is much more complex.
You could implement "for i in ..." using them, but this would be a bad
example, because as a non-strict (think "lazy") language it will handle
this code gracefully by default.
For example this code prints consecutive positive Integers starting from
1 (if run in the IO monad):
mapM_ print [1..]
If mapM_ scares you, you can define
for l f = mapM_ f l
and write it nicely as:
for [1..] print
Besides, Haskell macros aren't applied everywhere by default as in LISP.
You have to ,,splice'' them explicitely (see the paper).
A good example of TH's power is the ability to create a statically
type-checked printf mechanism using format strings like in C. Example:
$(printf "an int: %d, int in hex: %08x, a string: %20s") 10 255 "foo"
compiles and evaluates to
"an int: 10, int in hex: 000000ff, a string: foo"
but
$(printf "an int: %d, int in hex: %08x, a string: %20s") 10 "foo" 255
will raise a compile-time type error.
Recently I have used TH to generate a datatype enumeration all keywords
in some SQL dialect and to create a mapping from strings to these
datatypes. It looks like this:
keywords :: [String]
keywords = words
" ADD ALL ALTER AND ANY AS ASC AUTHORIZATION BACKUP BEGIN BETWEEN \
[... 160 keywords snipped ...]
\ VALUES VARYING VIEW WAITFOR WHEN WHERE WHILE WITH WRITETEXT "
kwConName :: String -> String
kwConName = id
-- generates abstract syntax for declaration of Keyword datatype
dataKeyword :: Dec
dataKeyword =
Data
[] -- context
"Keyword" -- datatype name
[] -- type variables
(map (\k -> Constr (kwConName k) []) keywords) -- constructors
(words "Show Eq Ord Enum Bounded") -- derived instances
-- generates abstract syntax for a list of pairs like ("SELECT", SELECT)
-- for all keywords
keywordMapList :: ExpQ
keywordMapList =
foldr
(\k l ->
let str = return (Lit (String k))
con = return (Con (kwConName k))
in [| ($str, $con) : $l |])
[| [] |]
keywords
Then in another module:
$(return [dataKeyword])
keywordMap :: FiniteMap String Keyword
keywordMap = listToFM $(keywordMapList)
This way I am sure that every keyword is included in the mapping.
Best regards,
Tom
--
.signature: Too many levels of symbolic links
More information about the Python-list
mailing list