Sven Panne writes:
> 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
> % ]
> ----------------------------------------------------------------------
>
...
> %const Int MouseButton(Eq,Ord) [ GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON,
>GLUT_RIGHT_BUTTON ]
Nice suggestion - I've implemented something v. close to it, %enum:
%enum MouseButton (Eq,Ord) Int [ GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON,
GLUT_RIGHT_BUTTON ]
which will generate the Haskell type
data MouseButton
= LeftButton | MiddleButton | RightButton
deriving (Eq, Ord)
marshall_MouseButton :: MouseButton -> Int
marshall_MouseButton = ...
unmarshall_MouseButton :: Int -> MouseButton
unmarshall_MouseButton = ...
plus implicitly create the DIS:
%dis mouseButton x = <marshall_MouseButton/unmarshall_MouseButton> (int x)
A new GC2 snapshot that includes support for %enum is now
(finally) available, see
ftp://ftp.dcs.gla.ac.uk/pub/haskell/glasgow/green-card/
BTW, the snapshot includes a new lexer, so there might be a lexing
buglet or two lurking in there..
--Sigbjorn
Re: name mangling, the snapshot also support the (snappily named)
cmd-line option:
--name-mangling-scheme={std,classic}
which control the mapping from external to Haskell names, i.e.,
A_NAME std
======> a_NAME
classic
======> aName (AName for constructors)
The default is std.