[Haskell-cafe] Re: A thought about liberating Haskell's syntax

George Pollard porges at porg.es
Wed Sep 16 08:36:01 EDT 2009


Just occurred to me that you can actually do this with a preprocessor.
If we extract the "template" declarations to a separate module, then
it can happen something like this (I have corrected some errors in the
above code):

---- main.hs ----

import Language.Haskell.TH
import QList
import Control.Monad

{-

pretend we had this:

main = do
	print (1,2,3)
	print (1)
	print (1,(2,3))
	print ((1,2),3)

- "template_outfix_lparen_rparen_expression" matches normal parens in
the expression context
- we also have a template operator for commas

The rules for the preprocessor are: inputs to the templates are always
wrapped in [| |].
The templates are wrapped in $().

This explains some of the extraneous nesting below (trying to pretend
I'm a machine!)

-}

main = do
	print $(
	 template_outfix_lparen_rparen_expression `fmap` [|
	  $( comma `fmap` [| 1 |] `ap` (comma `fmap` [| 2 |] `ap` [| 3 |]) )
	 |])
	print $(
	 template_outfix_lparen_rparen_expression `fmap` [|
	  $( [| 1 |] )
	 |])
	print $(
	 template_outfix_lparen_rparen_expression `fmap` [|
	  $( comma `fmap` [| 1 |] `ap` [|
	  	$(template_outfix_lparen_rparen_expression `fmap` [| $( comma
`fmap` [| 2 |] `ap` [| 3 |]) |] ) |] )
	 |])
	print $(
	 template_outfix_lparen_rparen_expression `fmap` [|
	  $( comma `fmap` [| $( template_outfix_lparen_rparen_expression
`fmap` [| $(comma `fmap` [| 1 |] `ap` [| 2 |]) |] ) |]
	  	`ap` [| 3 |]  )
	 |])

---------------------- QList.hs -------------------------------
{-
contains the templates and QList.
(the module created by preprocessor would usually only include
templates, with QList being a helper module)
-}

module QList
where
import Debug.Trace
import Language.Haskell.TH

data QList a = QCons a (QList a) | QNil

comma :: Exp → Exp → Exp
a `comma` b@(AppE (AppE (ConE x) _) _)
	| x == qconsName = a `qcons` b
	| otherwise      = a `qcons` (b `qcons` qnil)
a `comma` b = a `qcons` (b `qcons` qnil)

qnil :: Exp
qnil = ConE (mkName "QNil")

qcons :: Exp → Exp → Exp
a `qcons` b = (ConE (mkName "QCons")) `AppE` a `AppE` b

template_outfix_lparen_rparen_expression :: Exp → Exp
template_outfix_lparen_rparen_expression x = case x of
	(AppE (AppE (ConE y) _) _) → if y == qconsName
		then TupE $ fromQList x
		else x
	_                 → x

fromQList :: Exp → [Exp]
fromQList (AppE (AppE (ConE c) h) t)
	| c == qconsName = h:fromQList t
	| otherwise      = error "malformed qlist (head)"
fromQList (ConE n)
	| n == mkName "QNil" = []
	| otherwise = error "malformed qlist (tail)"

qconsName = mkName "QCons"


More information about the Haskell-Cafe mailing list