Try making a type class for the functions.&nbsp; That will allow you both varargs and unions.<br>Have a look at Text.Printf.<br><br>&nbsp; -- Lennart<br><br><div class="gmail_quote">On Sat, May 10, 2008 at 1:28 PM, Eric Stansifer &lt;<a href="mailto:eric.stansifer@gmail.com">eric.stansifer@gmail.com</a>&gt; wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">I have been trying to write a DSL for Povray (see <a href="http://www.povray.org" target="_blank">www.povray.org</a>) in<br>

Haskell, using the technique of:<br>
<a href="http://okmij.org/ftp/papers/tagless-final-APLAS.pdf" target="_blank">http://okmij.org/ftp/papers/tagless-final-APLAS.pdf</a><br>
with some inspiration taken from<br>
<a href="http://okmij.org/ftp/Haskell/DSLSharing.hs" target="_blank">http://okmij.org/ftp/Haskell/DSLSharing.hs</a><br>
<br>
The Povray Scene Description Language is a very declarative language,<br>
with few high level constructs (even loops take a bit of work) --<br>
which is why I&#39;m putting it in Haskell.<br>
<br>
At one point, I needed a &quot;varargs&quot; function for the DSL, a function f<br>
:: b -&gt; a -&gt; b dressed up to take a variable number of &#39;a&#39;s, known at<br>
compile time. &nbsp;This was easy enough:<br>
<br>
&gt; data Nil a = Nil<br>
&gt; data Cons b a = a ::: b a<br>
&gt; infixr 1 :::<br>
&gt;<br>
&gt; class VarArgs v where<br>
&gt; &nbsp; apply_args :: (s -&gt; a -&gt; s) -&gt; s -&gt; v a -&gt; s<br>
&gt;<br>
&gt; instance VarArgs Nil where<br>
&gt; &nbsp; apply_args _ start _ = start<br>
&gt;<br>
&gt; instance VarArgs b =&gt; VarArgs (Cons b) where<br>
&gt; &nbsp; apply_args f start (a ::: b) = apply_args f (f start a) b<br>
<br>
The solution is quite workable: &nbsp;I can simply write the following, and<br>
I believe the summation is expanded out at compile-time:<br>
<br>
&gt; apply_args (+) 0 (2 ::: 3 ::: 8 ::: 1 ::: (-3) ::: Nil)<br>
<br>
But I found I also needed a function to take a union type -- that is,<br>
the function would either take an argument of type T1, or of type T2,<br>
known at compile time. &nbsp;I tried a similar technique as I tried with<br>
varargs, and unfortunately ended up with this:<br>
<br>
&gt; data LeftOf a b = L a<br>
&gt; data RightOf a b = R b<br>
&gt;<br>
&gt; class Union u where<br>
&gt; &nbsp; apply_union :: (a -&gt; c) -&gt; (b -&gt; c) -&gt; (u a b) -&gt; c<br>
&gt;<br>
&gt; instance Union LeftOf where<br>
&gt; &nbsp; apply_union f _ (L a) = f a<br>
&gt;<br>
&gt; instance Union RightOf where<br>
&gt; &nbsp; apply_union _ g (R b) = g b<br>
&gt;<br>
&gt; type A = Integer<br>
&gt; type B = String<br>
&gt; type C = ()<br>
&gt;<br>
&gt; type Union_ABC u1 u2 = u1 A (u2 B C)<br>
&gt;<br>
&gt; f_A = show . (+ 3)<br>
&gt; f_B = reverse<br>
&gt; f_C = const &quot;unit&quot;<br>
&gt;<br>
&gt; f :: (Union u1, Union u2) =&gt; Union_ABC u1 u2 -&gt; String<br>
&gt; f = apply_union f_A (apply_union f_B f_C)<br>
&gt;<br>
&gt; main = do<br>
&gt; &nbsp; putStrLn $ f $ (L 6 :: Union_ABC LeftOne LeftOne)<br>
&gt; &nbsp; putStrLn $ f $ R (L &quot;hello, world&quot;)<br>
&gt; &nbsp; putStrLn $ f $ R (R ())<br>
<br>
Notice a lot of ugliness in my example: &nbsp;e.g., the definition of f,<br>
the type signature of f (I can&#39;t move the context into the<br>
type-synonym Union_ABC), creating objects of the union type, and the<br>
unpleasant surprise that I needed to provide the type of &#39;L 6&#39;. &nbsp;This<br>
solution is very not-scalable: &nbsp;the Povray SDL is a &quot;messy&quot; language,<br>
and for my DSL I would need approximately 20 or 30 such unions, each a<br>
union of about 20 types (admittedly with a lot of overlap from union<br>
to union).<br>
<br>
I think the solution is to abandon the lofty ideal of statically<br>
determining argument types; &nbsp;instead have a universal type with tags<br>
to distinguish types dynamically:<br>
<br>
&gt; data Universal = UA A | UB B | UC C<br>
&gt; f :: Universal -&gt; String<br>
&gt; f (UA a) = f_A a<br>
&gt; f (UB b) = f_B b<br>
&gt; f (UC c) = f_C c<br>
&gt;<br>
&gt; main2 = do<br>
&gt; &nbsp; putStrLn $ f $ UA 6<br>
&gt; &nbsp; putStrLn $ f $ UB &quot;hello, world&quot;<br>
&gt; &nbsp; putStrLn $ f $ UC ()<br>
<br>
...but I&#39;m not ready to give up hope yet. &nbsp;Suggestions please?<br>
<br>
Eric<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</blockquote></div><br>