GreenCard makes calling C fun again, but there is a feature which
is IMHO too low level: %const   Let me elaborate a little bit on this:

C lacks the concept of algebraic data types and has only very basic
support for enumeration types (via #define or enum), which can be
mixed quite happily with integers. Haskell is much cleaner in this
respect, so the following code should be considered bad style:

----------------------------------------------------------------------
%prefix GLUT_

%const Int [ GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON ]
----------------------------------------------------------------------

With the above code one gets values of type

   lEFT_BUTTON, mIDDLE_BUTTON, rIGHT_BUTTON :: Int

and can write embarrassing things like

   lEFT_BUTTON + mIDDLE_BUTTON

So the next try is probably:

----------------------------------------------------------------------
%prefix GLUT_

newtype MouseButton = MouseButton Int
%dis mouseButton x = MouseButton (int x)

%const MouseButton [ GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON ]
----------------------------------------------------------------------

This is a little bit better:

   * Addition of mouse buttons is now impossible.

   * If MouseButton is exported as an abstract type, the user can't
     construct new values of type MouseButton or do some fiddling
     with its internal representation.

But the last point is a weakness, too, because pattern matching on
mouse buttons is not possible anymore. The programmer is forced to
write ugly code like this:

   foo button | button == lEFT_BUTTON = ...

(assuming instance Eq of MouseButton) instead of the far more natural

   foo LeftButton = ...

In a nutshell: I simply don't want Ints everywhere in my Haskell code!

What to do? First step: Read GreenCard manual carefully...  :-]
Second step: Code your own marshalling/unmarshalling:

----------------------------------------------------------------------
%prefix GLUT_

data MouseButton = LeftButton | MiddleButton | RightButton

%const Int [ GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON ]

%dis mouseButton x = (< marshall_MouseButton / unmarshall_MouseButton > (int x))

marshall_MouseButton :: MouseButton -> Int
marshall_MouseButton LeftButton   = lEFT_BUTTON
marshall_MouseButton MiddleButton = mIDDLE_BUTTON
marshall_MouseButton RightButton  = rIGHT_BUTTON

unmarshall_MouseButton :: Int -> MouseButton
unmarshall_MouseButton x = head [ z | (y,z) <- table, x == y ]
   where table = [(lEFT_BUTTON,   LeftButton),
                  (mIDDLE_BUTTON, MiddleButton),
                  (rIGHT_BUTTON,  RightButton)]
----------------------------------------------------------------------

This code works, but given the simple task, it's a little bit long
and provokes quite a lot of hard to find typos. But hey, we can use
computers for this boring, repetitive stuff! So here is my proposed
extension for GreenCard: Let %const do all the dirty things for us,
allowing the whole above code to be written as:

----------------------------------------------------------------------
%prefix GLUT_

%const Int MouseButton [
%   LeftButton   = GLUT_LEFT_BUTTON,
%   MiddleButton = GLUT_MIDDLE_BUTTON,
%   RightButton  = GLUT_RIGHT_BUTTON
% ]
----------------------------------------------------------------------

What about derived instances? No problem: Suppose you wanted to
derive Eq and Ord. Just write

   %const Int MouseButton(Eq,Ord) [...]

And one last thing concerning naming conventions: C constants are
usually written in the form FOO_BAR_BAZ, while Haskell constructors
are normally named FooBarBaz. If the name mangling for %const took
care of this, all of the above code would boil down to a two-liner:

----------------------------------------------------------------------
%prefix GLUT_

%const Int MouseButton(Eq,Ord) [ GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, 
GLUT_RIGHT_BUTTON ]
----------------------------------------------------------------------

I know it's not Christmas yet, but this is one of the things placed
very high on my list of wishes...    :-)

-- 
Sven Panne                                        Tel.: +49/89/2178-2235
LMU, Institut fuer Informatik                     FAX : +49/89/2178-2211
LFE Programmier- und Modellierungssprachen              Oettingenstr. 67
mailto:[EMAIL PROTECTED]            D-80538 Muenchen
http://www.pms.informatik.uni-muenchen.de/mitarbeiter/panne

Reply via email to