Difference between revisions of "User:JRV"
Jump to navigation
Jump to search
(Got rid of draft tutorial) |
|||
(5 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | I'm developing a tutorial on this page (slowly). I'm keeping it here so I can check out |
||
− | format, figures, etc. before putting the whole think in the Tutorial area. |
||
− | |||
− | -------------------------------------------------------------- |
||
− | == Why? == |
||
− | Why would you want to do this? Those with Xcode/Cocoa experience will not |
||
− | need an explanation. On the chance that someone else is browsing here, |
||
− | I'll list a few things. |
||
− | |||
− | * Cocoa is not a language, it is a vast library of Objective-C objects. |
||
− | |||
− | * Cocoa covers tasks such as: |
||
− | ** windowing, |
||
− | ** displaying tables, outlines, trees, |
||
− | ** text fields (with built in editing), |
||
− | ** pretty easy printing, with pdf automatically available, and |
||
− | ** on and on... |
||
− | |||
− | * Objective-C is built on C, and is basically syntactic sugar for C. |
||
− | |||
− | Together with Interface Builder, one can define most user interfaces with |
||
− | simple drag and drop from a library of element, then connect them with your |
||
− | code by dragging and drop in the IB screen. |
||
− | |||
− | You automatically get full integration with the Mac system. You get the |
||
− | Mac Aqua look. |
||
− | |||
− | Enough said. What Cocoa doesn't provide are the tools for mathematical |
||
− | modeling of an application domain that Haskell provides. Parsing comes |
||
− | immediately to mind. |
||
− | |||
− | In the interest of full disclosure—I'm not an old time Mac person. I've |
||
− | had my Mac for two years. I only decided to learn Objective-C and Cocoa |
||
− | after I explored doing an application using Python and Qt, and someone in |
||
− | the Python community said “Objective-C is easy. Why don't you write a real |
||
− | Mac application”. Neither am I a Haskell expert. Although I've tinkered |
||
− | with Haskell for a long time (and it is probably my favorite language), |
||
− | I've just come back to it after a couple years away. |
||
− | |||
− | == Overview == |
||
− | [[image:JRV_CocoaHaFib_before.png|thumb|350px|right]] |
||
− | Here are screen shost of the simple application we will develop. The first |
||
− | shows the application widow (together with the menu automatically generated |
||
− | by Xcode), ready to enter a number. |
||
− | |||
− | The second shows the same scene after entering a number in the text box, |
||
− | and pressing “return”. |
||
− | |||
− | The entire user interface was built in a short time using the graphical |
||
− | Interface Builder, by dragging text the entry box, and the labels from a |
||
− | library of “controls” onto the window. Notice that the labels are dynamic, |
||
− | in the line “Fibonacci Number for n = … is: … ”. |
||
− | |||
− | I won't discuss Interface Builder any further in this tutorial. |
||
− | |||
− | [[image:JRV_CocoaHaFib_after.png|thumb|350px|center]] |
||
− | |||
− | == The Haskell module == |
||
− | For this test I used the same code as used in |
||
− | [[Calling_Haskell_from_C|Calling Haskell from C], with some slight |
||
− | modifications. Here is the Haskell code, in a file called ''FibTest.hs''. |
||
− | |||
− | <haskell> |
||
− | |||
− | {-# LANGUAGE ForeignFunctionInterface #-} |
||
− | |||
− | module FibTest where |
||
− | |||
− | import Foreign.C.Types |
||
− | |||
− | fibonacci :: Int -> Int |
||
− | fibonacci n = fibs !! n |
||
− | where fibs = 0 : 1 : zipWith (+) fibs (tail fibs) |
||
− | |||
− | fibonacci_hs :: CInt -> CInt |
||
− | fibonacci_hs = fromIntegral . fibonacci . fromIntegral |
||
− | |||
− | foreign export ccall fibonacci_hs :: CInt -> CInt |
||
− | |||
− | </haskell> |
||
− | |||
− | We compile this with ghc, viz: |
||
− | |||
− | $ ghc -c -O FibTest.hs |
||
− | |||
− | This produces the following files that we will import into Xcode: |
||
− | |||
− | * ''FibTest.o'' |
||
− | * ''FibTest_stub.h'' |
||
− | * ''FibTest_stub.o'' |
||
− | |||
− | and the following files that we won't need: |
||
− | |||
− | * ''FibTest_stub.c'' |
||
− | * ''FibTest.hi'' |
||
− | |||
− | == Import into Xcode project == |
||
− | First we start an Xcode project in the usual way. I started this as a |
||
− | plain Cocoa application. I called my application CocoaHaskellFib. |
||
− | |||
− | Several steps can be done in any order: |
||
− | |||
− | === Copy Files === |
||
− | FibTest.o, FibTest_stub.h, and FibTest_stub.o into the folder where |
||
− | you have saved your CocoaHaskellFib project. |
||
− | |||
− | Then add them to the project by Project ➝ Add To Project . |
||
− | |||
− | === Create application class === |
||
− | Next, create a Cocoa Objective-C class using the Xcode menu, File→New. |
||
− | I named mine CocoaFib. Xcode will create both an interface file (.h) and an |
||
− | implementation file (.m). |
||
− | |||
− | Here is my interface file: |
||
− | |||
− | <pre> |
||
− | #import <Cocoa/Cocoa.h> |
||
− | |||
− | |||
− | @interface CocoaFib : NSObject { |
||
− | IBOutlet NSTextField *integerInput; |
||
− | IBOutlet NSTextField *fibOutput; |
||
− | IBOutlet NSTextField *forNis; |
||
− | |||
− | } |
||
− | |||
− | -(IBAction)generate:(id)sender; |
||
− | |||
− | |||
− | @end |
||
− | </pre> |
||
− | |||
− | The three outlets are for the user input, fibonacci number output, and the |
||
− | label. |
||
− | |||
− | And here is my implementation code: |
||
− | |||
− | <pre> |
||
− | #import "CocoaFib.h" |
||
− | #include "HsFFI.h" |
||
− | #include "FibTest_stub.h" |
||
− | |||
− | @implementation CocoaFib |
||
− | |||
− | -(IBAction)generate:(id)sender{ |
||
− | int i = [integerInput intValue]; |
||
− | NSLog(@" in generate, integer input is %d\n",i ); |
||
− | unsigned int j = fibonacci_hs(i); |
||
− | [forNis setIntValue:i]; |
||
− | [fibOutput setIntValue:j]; |
||
− | |||
− | } |
||
− | |||
− | |||
− | -(void)dealloc{ |
||
− | hs_exit(); |
||
− | [super dealloc]; |
||
− | } |
||
− | |||
− | |||
− | @end |
||
− | |||
− | </pre> |
||
− | |||
− | Note the include lines for 1) ''hsFFI.h'', and ''FibTest_stub.h''. |
||
− | |||
− | Note also the ''hs_exit'' call in ''dealloc''. |
||
− | |||
− | === Modify main.m === |
||
− | When creating a Cocoa project, Xcode automatically generates a file |
||
− | ''main.m''. Normally, one never touches this file. However, when using |
||
− | a Haskell module, one needs to initialize the Haskell run-time by calling |
||
− | ''hs_init''. Normally, I would do this in an ''init'' call of |
||
− | ''CocoaFib.m'', rather than in ''main.m'', but since ''hs_init'' needs an |
||
− | ''argc'' and ''argv'', and since ''main.m'' already has them hanging |
||
− | around, I took the easy way out. |
||
− | |||
− | Here is ''main.m'' |
||
− | |||
− | <pre> |
||
− | #import <Cocoa/Cocoa.h> |
||
− | #include "FibTest_stub.h" |
||
− | |||
− | int main(int argc, char *argv[]) |
||
− | { |
||
− | hs_init(&argc, &argv); |
||
− | return NSApplicationMain(argc, (const char **) argv); |
||
− | } |
||
− | |||
− | |||
− | </pre> |
||
− | |||
− | The only changes to the main.m provided by Xcode are the addition of |
||
− | ''include "FibTest_stub.h"'' and the call to ''hs_init''. |
||
− | |||
− | == Compile and run == |
||
− | This is the easy part. Just kidding. It should be easy, if it were easy |
||
− | to make a library or executable containing ''FibTest.o'', |
||
− | ''FibTest_stub.o'' and all their dependencies. Unfortunately I've been |
||
− | unable to do that, in spite of spending most of my spare time for a week |
||
− | trying, and posting questions on ''Haskell-cafe''. |
||
− | |||
− | Anyway, here is how I did it. If you have a better way, here is a good |
||
− | place to edit this tutorial! |
||
− | |||
− | === Build and go, the first time === |
||
− | === Iterate build and go === |
||
− | === Symlink renamed libgmp.a === |
||
− | == To do == |