|
HOC: A Haskell to Objective-C Binding |
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
| HOC: a Haskell to Objective-C bridge |
- Introduction
- Quick Start
- Mapping Objective-C Concepts to Haskell
- Objects & Classes
- Object Messaging
- Sending Messages to Objects
- Message Chaining
- Ambiguous Function Names
- Selectors
- Foundation & AppKit Frameworks
- Miscellanea
- Accessing Other Frameworks from Haskell
- Creating an Objective-C Class in Haskell
- Tools
- Appendices
Introduction
HOC is a Haskell to Objective-C binding. In a nutshell, it enables you to use Objective-C objects and frameworks from Haskell, and also enables you to write Objective-C objects in Haskell. The Haskell interfaces produced by HOC are:
- Strongly Typed
While Objective-C is a typed language, it is weakly typed (since
it is based on C, which is also weakly typed language), and
dynamically typed. Haskell is a statically, strongly typed
language, and HOC uses this to its advantage: the Haskell
interfaces generated by HOC are heavily typed, and map closely to
Objective-C's concepts.
- Automatically Generated
HOC uses an interface generator that parses Objective-C header
files to produce Haskell source code. The Haskell code contains
data types representing the Objective-C class hierarchy, and
methods and selectors which enable HOC to communicate with
Objective-C frameworks. If you are familiar with other Haskell
interface generators such as c2hs
<http://www.cse.unsw.edu.au/~chak/haskell/c2hs/> or
GreenCard <http://www.haskell.org/greencard/>, HOC's
ifgen tool does the same job, but for creating bindings to
Objective-C classes instead.
- Haskell-Friendly
HOC was designed from the very beginning to be as 'Haskell-like'
as possible: after all, you are writing Haskell code, not
Objective-C code! We make heavy use of key Haskell features such
as type classes and partial application, to ensure that you don't
have to do evil things like method name mangling or understand
a whole new bunch of syntax, just to do something simple like
embed an NSMovie in your application.
For example, to allocate a new object, you can send the alloc
message to an Objective-C object. More specifically, you are
required to send alloc to a class object: [NSMovie
alloc], in Objective-C syntax. In HOC, sending alloc to
a non-class object is a compile-time error, because alloc is
not defined for non-class objects. Of course, since Objective-C
uses dynamic binding, HOC still enables you to send arbitrary
messages to any object via a generic sendMsg function, but the
normal way to send messages to objects with HOC are all strongly
typed.
In practical terms, this means that you gain all the benefits of a modern type system: Haskell's type inference is applied to everything from message sending operations to maintaining an object-oriented class hieararchy. As a result, you produce programs that are safer and work correctly on the first succesful compilation a disturbingly large percentage of the time.
By default, HOC is configured to build bindings for the Foundation and AppKit frameworks (collectively named Cocoa on Mac OS X), but you can build your own bindings with ifgen if required.
HOC's primary platform is Mac OS X, Apple's modern UNIX-based operating system. However, HOC does provides preliminary support for the GNUstep platform <http://www.gnustep.org/>, and has been lightly toasted, err, tested, with GNUstep on Linux.
Requirements
HOC requires the Glasgow Haskell Compiler (GHC) 6.2 <http://www.haskell.org/ghc/> or later to build. We use the latest features provided by GHC, such as Template Haskell, to implement many parts of HOC, and it would be impossible (as opposed to just plain hard) to port these implementations to work with older versions of GHC.
Assumed Knowledge
Let's get something straight here: HOC isn't for the beginner Haskell or Objective-C developer. You are required to know basic Objective-C concepts such as what classes, methods, messages and selectors are, and ideally will have written a few Objective-C programs to understand how to use all these concepts in practice. You should also be comfortable with programming in Haskell, in particular how to program with IO in Haskell (meaning that you should have actually written a few Haskell tools which use IO). That doesn't mean you have to understand monads, by the way. Hell, this author has done IO in Haskell for years and doesn't pretend to understand monads ...
Quick Start
A Simple Commandline Tool
Apple provides the source code for a ``Simple Cocoa Command-Line Tool'', which performs uniquing and sorting on a list of arguments. You can find the original code at: http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaObjects/Articles/SimpleCocoaTool.html
To give you an idea of what HOC code looks like, here's
a line-by-line translation of the Objective-C code that's as
close to the original as we can get (even trying to do silly
things like emulate a while() loop):
module Main where
-- #import <Foundation/Foundation.h>
import Foundation
import Foundation.NSProcessInfo (arguments)
-- We need this import to disambiguate the 'arguments'
-- function: an 'arguments' method is defined in many
-- classes, including NSProcessInfo, NSScriptCommand,
-- and NSTask. Any ambiguous functions are not exported
-- by the framework by default: you will need to
-- import those functions explicitly.
import HOC
-- int main (int argc, const char * argv[]) {
main = do
-- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-- ...
-- [pool release];
withAutoreleasePool main'
main' = do
-- NSArray *args = [[[NSProcessInfo processInfo] arguments];
args <- _NSProcessInfo # processInfo >>= arguments
-- NSCountedSet *cset = [[NSCountedSet alloc] initWithArray:args];
cset <- _NSCountedSet # alloc >>= initWithArray args
-- NSArray *sorted_args = [[cset allObjects]
-- sortedArrayUsingSelector:@selector(compare:)];
sorted_args <- cset # allObjects
>>= sortedArrayUsingSelector (getSelectorForName "compare:")
-- NSEnumerator *enm = [sorted_args objectEnumerator];
enm <- sorted_args # objectEnumerator
-- id word;
-- while (word = [enm nextObject]) {
-- printf("%s\n", [word UTF8String]);
-- }
let loop = do
word <- enm # nextObject
if (not (isNil word))
then do { putStrLn ( (fromNSString.castObject) word ); loop }
else do return ()
in
loop
-- [cset release];
-- Don't need to release anything: HOC manages memory for you via
-- Haskell's garbage collector!
-- return 0;
return ()
-- }
The code is available in the Samples/UniqSort/ directory of the HOC source distribution if you'd like to compile it and try it for yourself:
~hoc/Samples/UniqSort % ./uniqsort a z c a l q m z
/Users/... # This appears because it's part of the program's
# argument list!
a
c
l
m
q
z
Hopefully, the code listing above will give you a good idea about how to write Haskell code that sends messages to Objective-C objects. For more detail, see the chapter on Mapping Objective-C Concepts to Haskell.
A Simple GUI Application
Preface: This section presumes that you've written a Cocoa application before with Objective-C, so that you understand the basic development process and design patterns involved with Cocoa programs, such as Model-View-Controller and how to use Interface Builder. If you don't know any of this, you'll have to do some background reading on Cocoa. Apple provides a simple tutorial at http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCTutorial/index.html, but if you're after something more comprehensive, this author has read and highly recommends the book ``Cocoa Programming for Mac OS X'', by Aaron Hillegass: http://www.bignerdranch.com/products/cocoa1.shtml.
Say you've got a simple Haskell module: for this example, we'll use the ExpressionParser.hs module from the Samples/ExpressionParser directory of the HOC source distribution. The code is short and schweet:
module ExpressionParser
where
import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Expr
expr :: Parser Integer expr = buildExpressionParser table factor <?> "expression"
table = [ [op "*" (*) AssocLeft, op "/" div AssocLeft]
, [op "+" (+) AssocLeft, op "-" (-) AssocLeft] ]
where
op s f assoc = Infix (do { string s; return f }) assoc
factor = do { char '('; x <- expr; char ')'; return x }
<|> number
<?> "simple expression"
number :: Parser Integer
number = do { ds <- many1 digit; return (read ds) } <?> "number"
Now, you want to wrap a GUI around this module so that people can use it without loading GHC or the Apple Terminal application: see http://localhost/~andrep/hoc/screenshots/ExpressionParser_view.png for a screenshot of what the GUI will look like. From a programing perspective, the GUI consists of:
- An expressionEntry outlet
- This is where the user types in the expression which they want the answer to.
- An evaluateExpression action
- The method which will be called when the user clicks on the button, or presses Enter in the expressionEntry text field.
- An evaluation outlet
- Where the answer to the expression evaluation will be displayed.
For this example, we assume that you've created and instantiated
an EPController object in Interface Builder which the GUI view
will be connected to. The question is, of course: how do you
write this EPController object in Haskell? The answer: like
this ...
{-# OPTIONS -fglasgow-exts #-}
module EPController where
import Cocoa hiding (parse) import ExpressionParser import Selectors import Text.ParserCombinators.Parsec (parse)
$(declareClass "EPController" "NSObject")
$(exportClass "EPController" "ep_"
[ Outlet "expressionEntry" [t| NSTextField () |]
, Outlet "evaluation" [t| NSTextField () |]
, InstanceMethod Selectors.info_evaluateExpression ])
obj #. var = obj # getIVar var
ep_evaluateExpression _ self = do
-- Get the expressionEntry outlet text field from this object, and get
-- what the user typed as a Haskell string
expression <- self #. _expressionEntry >>= stringValue >>= haskellString
-- Parse the expression
case (parse expr "" expression) of
Left err ->
-- Parsing returned an error: display it in the output text field
self #. _evaluation >>= setStringValue (toNSString $ "Error " ++ show err)
Right answer ->
-- Parsing was successful: display the answer
self #. _evaluation >>= setStringValue (toNSString $ show answer)
Additionally, you'll need to write a Selectors.hs module, which
contains any additional selector names that aren't in Cocoa.
This enables HOC to statically type check your function names and
make sure that they exist. You can call the module whatever you
like: the important bit is that the declareSelector function
you'll be using must be in a different module from the
declareClass and exportClass functions, due to a limitation
of Template Haskell. e.g.:
{-# OPTIONS -fglasgow-exts #-}
module Selectors where
import AppKit.NSButton
$( declareSelector "evaluateExpression:" [t| forall a. NSButton a -> IO () |] )
That comprises the code for your graphical application. You'll still need to produce a .app application bundle to run your GUI application though: to do this, you could manually make the .app bundle, which is rather tedious. A better idea would be to use Xcode to generate a boilerplate bundle for you and customise that, or steal one of the directory layouts from one of HOC's sample applications (in the Samples/ directory). Once you've produced the Contents/ directory layout required for the bundle, you can then use the hocwrap tool (described in the Tools section) to wrap your Haskell executable in the final .app directory (or hand-roll it yourself, if you're into masochism).
For complete code examples, see the ExpressionParser, Browser, and Editor applications in HOC's Samples/ directory.
Mapping Objective-C Concepts to Haskell
Objects & Classes
Classes
An Objective-C class foo has a corresponding Haskell type
foo (): the type signature for a function which takes in an
NSArray (and only an NSArray) and outputs an NSMovie
will look like NSArray () -> NSMovie ().
To permit a function to use a NSArray or any of its subclasses
such as NSMutableArray (which is the behaviour you'd expect
from an object-oriented language), use a type variable in place
of the (): e.g. NSArray a.
Class Objects
Class objects are represented in HOC by preprending an underscore
to the class name: _classname. For example, to send the
alloc message to the NSMovie class object, write
_NSMovie # alloc.
Protocols & Protocol Adoptions
This section of the documentation hasn't been written yet, but in the meantime, you may find the following note from Wolfgang Thaller useful:
Yes, formal protocols. Luckily, they're very rarely used in Cocoa. It's only an ifgen issue; the current ifgen just generates ID for all id<Foo> types. For id<Foo,Bar> used as a parameter, it should generate (Foo (ID a), Bar (ID a)) => ID a. For return values id<Foo,Bar>, we'll have to define a special type ID_Bar_Foo and declare instances for Foo and Bar for it. The only difficult part should be to avoid defining those types too often...
Categories
This section is not written yet: please write to the hoc-users mailing list (see http://hoc.sourceforge.net/support.html) for assistance or, have a look at the HOC source code yourself.
Specific Classes
NSString vs. String
HOC provides the two functions toNSString :: String -> NSString
(), and fromNSString :: NSString () -> String, to
convert to and from Haskell strings and the Foundation
framework's NSString objects.
Note that fromNSString is a pure function, and that it will not
accept a subclass of NSString as an argument, because subclasses
may be mutable. Make sure you never pass a casted NSMutableString
to fromNSString.
If you want to work with (potentially) mutable string objects,
you can use the functions haskellString :: NSString a -> IO
String and stringWithHaskellString :: String ->
NSStringClass a -> IO (NSString a). Use them as if they were
Objective-C methods in the NSString class.
Object Messaging
Sending Messages to Objects
The Objective-C syntax [receiver method:arg1 with:arg2] that
is used to send a message to a receiving object, is translated to
Haskell as methodWith arg1 arg2 receiver.
The receiving object goes last in the parameter last, because
then you can use ye olde trick of defining an infix function ``x
# f = f x'' to produce the more object-oriented-looking code
receiver # methodWith arg1 arg2. (The # infix function is
defined for you by HOC already, so you don't need to define it
yourself).
Note that sending messages is an IO operation, so you'll need to
be in the IO monad to use it. Purely functional (non-mutable)
objects such as an NSArray or a NSString provide their own
specialised non-IO functions, which can be used outside of
monadic code. See their documentation (or source code
implementation) for details.
Message Chaining
Message chaining is a very common phenomenon in Objective-C:
syntactically, it looks like [[NSCountedSet alloc]
initWithArray:args]. You first send an alloc message to
the NSCountedSet (class) object, and then send
initWithArray:args to the result of that.
Experienced Haskell programmers will realise that this is
analagous to the monadic bind operator, >>=, so the
above message chain could be written as _NSCountedSet
# alloc >>= initWithArray args.
Ambiguous Function Names
Some functions have the same name and are defined in more than
one class: e.g. the NSProcessInfo, NSScriptCommand and
NSTask classes all define a method named arguments. Any
such multiply-occuring method names are not exported from the
top-level framework module (Foundation or AppKit) by
default: you will need to import the class specifically, e.g.
import Foundation.NSProcessInfo to import NSProcessInfo's
arguments function.
If you wish to use the arguments method from multiple classes,
use the import qualified or import X as Y constructs, just
as if you were importing a same-named function from different
Haskell modules normally.
Selectors
An Objective-C selector name is translated to a Haskell function name as follows:
- Colons (
:) disappear
-
e.g. The Objective-C method name ``
mouseDragged:'' is translated to ``mouseDragged''. - Initial lower-case characters after a colon (
:) become upper-case
-
e.g. The Objective-C method name ``
initWithURL:byReference:'' is translated to ``initWithURLByReference''. - Leading upper-case characters become lower-case
-
e.g. The Objective-C method name
``
TIFFRepresentationUsingCompression:factor:'' is translated to ``tiffrepresentationUsingCompressionFactor''.
Use the getSelectorForName :: String -> SEL function to
generate a Haskell SEL datatype from a raw Haskell string. As
you can guess, the Haskell SEL type is the same as
Objective-C's SEL type: it represents a selector (method
name).
Note that the string you pass to getSelectorForName is the
Objective-C selector name (with all the colons in the
appropriate places), not the translated Haskell function name.
For example, you should pass in "initWithURL:byReference:",
and not "initWithURLByReference".
Foundation & AppKit Frameworks
The Haskell interfaces for the Foundation and AppKit frameworks
(née Cocoa) are automatically built when you build and
install HOC. To use them, simply write import Foundation,
import AppKit or import Cocoa at the top of your Haskell
module to import the entire framework's class hierarchy and
method definitions into scope. (But, see the section on
Ambiguous Function Names to see why some methods are not
imported.)
To use your own, custom frameworks with HOC, see the chapter on Accessing Other Frameworks from Haskell.
Miscellanea
Autorelease Pools
Use the function withAutoreleasePool :: IO a to create an
autorelease pool and run an IO action which which use the pool:
main = do
withAutoreleasePool main'
main' = do
args <- _NSProcessInfo # processInfo >>= arguments
...
Using withAutoreleasePool instead of an explict alloc and
release for the pool saves you from remembering to
release it: after your action has been run, the pool is
automatically released.
enum Types
This section is not written yet: please write to the hoc-users mailing list (see http://hoc.sourceforge.net/support.html) for assistance or, have a look at the HOC source code yourself.
struct Types
This section is not written yet: please write to the hoc-users mailing list (see http://hoc.sourceforge.net/support.html) for assistance or, have a look at the HOC source code yourself.
Accessing Other Frameworks from Haskell
This section is not written yet: please write to the hoc-users mailing list (see http://hoc.sourceforge.net/support.html) for assistance or, have a look at the HOC source code yourself.
Creating an Objective-C Class in Haskell
As well as being able to use Objective-C classes in Haskell, HOC also enables you to create an Objective-C class in Haskell: you can subclass an existing Objective-C class, declare instance variables and methods in a class, and write code for it all in Haskell. You can even make your class the owner of an Interface Builder .nib file, and Interface Builder's outlets and actions can call methods in your class.
Programming Examples
If you're the type of person who learns best by following examples rather than reading documentation, HOC comes with two sample programs in the Samples/ directory of the HOC source code distribution:
- Editor:
A simple text editor, which loads and saves files with a .hs
extension. There are no fancy features in the editor, but it is
a full document-based application. The - Browser:
A simple class browser. It uses Objective-C's reflection
capabilities to query the Foundation and AppKit frameworks,
and displays all the Objective-C method names found, the
corresponding Haskell function name, the Haskell type, and which
class the method is defined in. (Note that this program might
take a while to start up and will bounce in the dock for a while,
because it's reading all the method names during startup.)
HaskellDocument class
included with this sample application is a subclass of
NSDocument, and implements methods used by a document-based
application, such as readFromFileOfType: and
windowControllerDidLoadNib:.
The Class Creation API
So, how do you create an Objective-C class in Haskell? The two
main HOC functions you will require are declareClass and
exportClass. Note that these functions are Template
Haskell (TH) functions, so you'll need to use Template Haskell's
special $(...) syntax to use them. (If you don't know what
Template Haskell is, see the Template Haskell in a Nutshell
appendix which gives a very quick overview about what it is.)
The declareClass Function
The declareClass function is somewhat analgagous to writing
the type signature for a function: in the same way that a type
signature tells the compiler that you intend to write the body of
a function later in the code, declareClass tells HOC that you
intend to define a class later in your code.
The type of declareClass is String -> String -> Q [Dec]. Its first argument is the name of the class that you wish to
write in Haskell, and the second argument is the name of an
existing Objective-C class that you want to subclass (such as
NSObject or NSDocument). You must declare an existing
class to subclass: you cannot currently create a new class which
sits at the root of an object hierarchy (such as NSObject or
NSProxy).
For example,
$(declareClass "MyDocument" "NSDocument")
declares a new class named MyDocument which is a subclass of NSDocument. (Imaginative, huh?)
The exportClass Function
After using the declareClass Template Haskell function to
declare a new Objective-C class, you can then export the
actual definition of the class with the exportClass function.
Here's the type of exportClass, which gives a very brief
overview of how to use it:
:: String -- ^ Name of the class you're exporting,
-- e.g. "MyDocument"
-> String -- ^ A prefix for function names which are
-- methods belonging to this class,
-- e.g. "md_"
-> [ClassMember] -- ^ A list of class members (see below for
-- example)
-> Q [Dec] -- ^ Code which produces a Haskell declaration,
-- which you can splice in with Template
-- Haskell's $(...) syntax
Here are the parameters you need to supply to exportClass in
a bit more detail:
String
The name of the class you're exporting (which must match the name
of a class you've declared previously with String
A methods prefix (string), which tells HOC what functions in
the current Haskell source file are methods belonging to the
exported class. HOC scans each function name in your Haskell
source file: every function name which begins with the methods
prefix you specify will be exported as a (class or instance)
method, belonging to the exported class.
[ClassMember]
This argument specifies what members the class should have, i.e.
instance methods, class methods, instance variables, and outlets.
The
declareClass),
For instance, if you declare and export a MyDocument class,
a sensible methods prefix could be md_. Then, any function
names which begins with md_ will be treated as a method for
that MyDocument class. For example, md_windowNibName or
md_windowControllerDidLoadNib would be methods of
MyDocument (and thus expected to have the proper type
signature for such a method), but wibble would not be.
ClassMember data structure is defined as:
data ClassMember = InstanceMethod SelectorInfo
| ClassMethod SelectorInfo
| Outlet String TypeQ
| InstanceVariable String TypeQ ExpQ
Hopefully the type information will inform you about what
arguments you need to provide to each of the data contructors to
produce a ClassMember.
Here's an example of what this particular argument might look like (taken directly from the Samples/Editor/HaskellDocument.hs file in the HOC source distribution):
[ Outlet "textView" [t| NSTextView () |] , InstanceVariable "text" [t| Maybe (NSString ()) |] [| Nothing |] , InstanceMethod info_windowNibName , InstanceMethod info_writeToFileOfType , InstanceMethod info_readFromFileOfType , InstanceMethod info_windowControllerDidLoadNib ]
The output type of exportClass is Q [Dec], which is code
that produces a Haskell declaration. You'll need to 'splice'
this code into your source file, by using Template Haskell's
$(...) syntax.
An Example
Putting it all together, here's a small example of how you might write a HaskellDocument class (which subclasses NSDocument) in Haskell:
import HOC
$(declareClass "HaskellDocument" "NSDocument")
$(exportClass "HaskellDocument" "hd_" [
Outlet "textView" [t| NSTextView () |],
InstanceVariable "text" [t| Maybe (NSString ()) |] [| Nothing |],
InstanceMethod info_windowNibName,
InstanceMethod info_writeToFileOfType,
InstanceMethod info_readFromFileOfType,
InstanceMethod info_windowControllerDidLoadNib
])
Declaring your own Selectors
The HaskellDocument class in the above example only
implemented methods whose types were already known because the
selector was already defined somewhere in Cocoa. If you've used
InterfaceBuilder to place a small button labelled with the Greek
letter Pi in the lower-left corner of your window and
connected it to a method named smallPiClicked:, then you'll
need to declare that selector yourself using the
declareSelector template function, which has the following
type:
:: String -- ^ The Objective-C selector name -> TypeQ -- ^ The method's type signature -> Q [Dec] -- ^ Code which produces a Haskell declaration
So for the smallPiClicked: selector you might write:
$( declareSelector "smallPiClicked:" [t| forall a. ID a -> IO () |] )
The Objective-C selector name ``smallPiClicked:'' will be
automatically mangled to smallPiClicked (as per the rules
given in the Selectors section above). If you don't like this,
you can use declareRenamedSelector instead:
$( declareRenamedSelector "smallPiClicked:" "haskellNameForThisSelector"
[t| forall a. ID a -> IO () |] )
Due to a limitation of Template Haskell, you cannot put this
declaration in the same module as your exportClass
declaration: you'll have to put them in another module and
import that module instead. (This is because identifiers
declared by Template Haskell ``splices'' are not available to other
splices within the same module.)
Tools
hocwrap
The hocwrap tool takes an executable and ``wraps'' it in a Mac OS
X .app application bundle. You'll need to tell hocwrap where the
bundle's Contents/ directory using the -c command-line parameter.
hocwrap can also run the resulting application bundle using GHCi in an
interactive fashion: more documentation about this will be coming in the
future, but for now, check out the Browser and Editor applications'
Makefiles in HOC's Samples/ directory, for an idea of how to use the
GHCi interaction feature.
See hocwrap --help for the definitive reference on hocwrap.
Appendices
Building HOC
HOC is distributed as a standard UNIX tarball (.tar.bz2 file), and uses GNU autoconf for its build system. Building HOC should be a simple matter of the standard autoconf build mantra:
./configure make make install
See the README.txt file in the HOC distribution for the most up-to-date build information.
Building HOC from a CVS repository is only slightly more involved: see the BUILDING.CVS file in your checked out CVS directory (which is not included in proper release tarball) for more information.
Template Haskell in a Nutshell
Template Haskell is an extension to Haskell 98 that allows you to do type-safe compile-time meta-programming, with Haskell both as the manipulating language and the language being manipulated. — from the Template Haskell webpage at <http://www.haskell.org/th/>.
From a HOC user's viewpoint, Template Haskell makes lots of
things possible in HOC that are not possible without it, and
greatly simplifies the HOC API that you use to declare new
classes. In the The Class Creation API section, the two
functions declareClass and exportClass ``template'' functions
were described. These are functions which have the mysterious
output type Q [Dec]: to put it simply, the output of these
template functions are actually Haskell code. Just as
functional languages such as Haskell can treat functions as
first-class entities, Template Haskell allows Haskell code to
be treated as a first-class entity: you can pass code around to
other functions, inspect the code, change it, and pass that new
code to yet more functions. (If you're familiar with compilers,
the code that's passed around is actually a data structure that
represents the abstract syntax tree: you can walk the tree and
add, change or remove nodes at your leisure.)
Of course, as well as manipulating code, you can also execute
these first-class code thingys, which is what the odd-looking
$(...) syntax does. That tells GHC to execute the code
fragment inside the brackets: in Template Haskell terminology,
this is called splicing in code. So, when you use template
functions such as exportClass, they actually generate code
based on the parameters you give it, and immediately splice the
code in, writing out possibly hundreds of declarations and
functions for you invisibly.
Of course, this appendix only covers Template Haskell as it applies to HOC: see the Template Haskell webpage (link given above) for more information on it, what you can do with it, and why it (and meta-programming in general) kicks ass.
History
A long time ago, in a galaxy far, far away ... err, wait, wrong chapter. Ahem.
The first development snapshot of HOC came out in January 2003, in a humble announcement to the glasgow-haskell-users mailing list by Wolfgang Thaller. While it worked, it was half of an experiment with Template Haskell, and half a proof-of-concept, rather than intending to be a proper language binding.
During HOC's development, another Haskell to Objective-C binding was being developed, named Mocha. Mocha was the result of André Pang's thesis on Binding Haskell to Object-Oriented and Component Systems <http://www.algorithm.com.au/files/reflection/reflection.pdf>, and it, like many thesis implementations, was also more of a proof-of-concept rather than a real, useful piece of software.
The authors of HOC and Mocha met at the Haskell Implementor's
Meeting in Stockholm, Sweden later in 2003, and sat down to try
to reconcile the two projects. HOC was a very different beast
from Mocha: HOC wasn't typed at all (e.g. all Objective-C objects
were represented using only the one ID type), for instance.
Mocha, being the result of a thesis on integrating Haskell with
object-oriented systems, was focused very much at bringing
object-oriented style overloading into the Haskell world.
Wolfgang Thaller did the heavy lifting and rewrote HOC from
scratch using many of the ideas from Mocha and Andr´'s
thesis, and the result is what you have today: a more supported,
stable Objective-C binding than would be possible without both
authors supporting each other.
| HOC: a Haskell to Objective-C bridge |



