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.

Reply via email to