Calling Haskell (1)

This post is going to be very boring.

BTW, all the info is contained inside the sample projects in GHC-iPhone release, I'm just documenting it to remember it better.

There's no wrapper to use for the iPhone SDK, so the programer will essentially be building a subset of Objective-C wrapper in C and manually creating tunnels to call these C functions in Haskell.

The task can be broken down into 3 Big steps:

1. Create

  • wrap an Objective-C method in C
  • import the C function into Haskell through FFI
  • create a function that utilize this imported function in Haskell

2. Export

  • create an empty function pointer in C
  • create a setter function to initialize this function pointer in C
  • import the setter function into Haskell
  • Use the setter to initialize a Haskell function

3. Use

  • somewhere in Objective-C, call into Haskell through this initialized function

Step 2 contains some boilerplates: the function pointer and initializer, so I wrote

OMG

my first C Macro! ><

1
2
3
4
5
6
7
8
9
10
/* 
H(draw_rect) ->

void (*draw_rect)(void);
void set_draw_rect(void (*cb)() {
draw_rect = cb;
}
*/

#define H(f) \ void (*f)(void);\ void set_##f(void (*cb)()) {\ f = cb;\ }

So my first experiment allows Haskell to draw a line in the view, here's the relavent code:

ScoreView.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@implementation ScoreView

void drawLine(double x0, double y0, double x1, double y1)
{
CGContextRef _context = UIGraphicsGetCurrentContext();
CGContextBeginPath(_context);
CGContextMoveToPoint(_context, x0, y0);
CGContextAddLineToPoint(_context, x1, y1);
CGContextStrokePath(_context);
}

H(draw_rect)

- (void)drawRect:(CGRect)rect {
if (draw_rect != nil) draw_rect();
}

@end

Main.hs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
foreign import ccall safe "drawLine" drawLine :: CDouble -> CDouble -> CDouble -> CDouble -> IO ()
foreign import ccall safe "wrapper" mkPlain :: IO () -> IO (FunPtr (IO ()))
foreign import ccall safe "set_draw_rect" set_draw_rect :: FunPtr (IO ()) -> IO ()


main = do
draw_rect <- mkPlain $ drawLine 0 0 220 220
set_draw_rect draw_rect

kon

free draw_rect

where
free = freeHaskellFunPtr
blog comments powered by Disqus