Embedding Haskell within Eiffel

by Colin Adams (modified: 2010 Jan 28)

Following on from my comment in my post about class fibonacci that Haskell manages integers better than we do, I extended my test program for Fibonacci numbers to make a call to a Haskell function.

Timings and output printing F(11199) (compiled with ISE 6.3) are:

Class FIBONACCI (FreeELKS) - 2ms prints: -1880045342

Class MA_DECIMAL - 22ms prints: 1.26793967E+2340

Haskell function - 18ms - prints all digits: (see end of article)

The interesting thing to me, was not the comparative speeds or accuracy of the last two results, but the ability to embed Haskell programs within Eiffel programs.

I did it (for now) using extern C inline calls, but also the Haskell source code is embedded within the Eiffel class, using one of the literate programming styles defined by the Haskell language. Namely that any source line not starting with a > character is commentary, not code.

Therefore I was able to make a symbolic link to the Eiffel source file (this won't work on windoze - what does?, but a system.xace file can make temporary copies, or supply a command line argument to tell the Haskell compiler to treat .e files as literate Haskell source), fib.e, as fib.lhs (Literate Haskell Source), and run the ghc complier over it to generate the C code stubs. Thus the C externals and Haskell source which they represent are tied together in the same file.

Here are the relevant portions of the Eiffel class:

feature {NONE} -- Haskell init_haskell is -- Initial Haskell runtime. external "C inline use <stdio.h>,%"HsFFI.h%"" alias "[ static char * program_name = "Eiffel program"; static char * terminator = (char *) 0; int argc; char **argv[2]; argc = 1; argv [0] = &program_name; argv [1] = &terminator; hs_init(&argc, argv); ]" end exit_haskell is -- Terminate all Haskell threads. external "C inline use <stdio.h>,%"HsFFI.h%"" alias "[ hs_exit(); ]" end haskell_fib (n: INTEGER): POINTER is -- String representation of `n'th Fibonacci number as a string external "C inline use <stdio.h>,%"HsFFI.h%"" alias "[ #ifdef __GLASGOW_HASKELL__ #include "Fib_stub.h" extern void __stginit_Fib ( void ); hs_add_root(__stginit_Fib); #endif return (fibonacci_hs($n)); ]" end haskell_source: STRING is "[ >{-# LANGUAGE ForeignFunctionInterface #-} > > module Fib where > > import Foreign.C.Types > import CString > > fibonacci :: Int -> String > fibonacci n = show (fibs !! n) > where fibs = 0 : 1 : zipWith (+) fibs (tail fibs) > > fibonacci_hs :: CInt -> IO CString > fibonacci_hs = newCString . fibonacci . fromIntegral > > foreign export ccall fibonacci_hs :: CInt -> IO CString ]" -- Source of Haskell functions

What would be really nice would be to skip the external C inline for the haskell_fib function (the init_haskell and exit_haskell functions can just be permanent features in a support class), and instead have the literate Haskell source in an external Haskell inline instead, just containing the Haskell code. It may well be possible to write Eiffel classes that allow to plug-in any external language in this way.

One possible design would be to have a class for each external language (a descendant of EXTERNAL_LANGUAGE perhaps), that, when the Eiffel compiler sees the tokens external Haskell inline calls the registered class for the language, passing it the inline contents, and expects back inline contents for external C inline from it.

I don't know if Eiffel compilers can cope with such a switch of input, but if so, I would be interested in implementing it.

F(11199) according to Haskell function: 12679384073815973372844318401862123783154826930997138787843633089 76639653296492606282446543143257044218551021161163143380933095690 76061692595362936849831945644877554556655782080011244472928203596 74396860478288496756184846094827214695157018509921499558298365341 38608899745118493209130210804454400980340326822381977121614232250 61273116863641864055783145892655887108329644457870261035233984544 94644187838412764394575895662032592490607757788559271830561737031 91534716085444638174022477499301646373490683795161261083152380975 77093701283469138512383856089101976851852730475537840890477714284 48115055386865813617968288917034554105240097152923149996559165022 92934610381683583564436371129313819996923327754432919967555097507 32696994996359608760893592283960424313044535468318503961943558764 82062548429326941336637982349809656135165379260850415078680553242 07753681201951100050455691543155355326133599130522841087765802690 15100160530471931347369375416781524644369413006118108983797838528 48631829581986216698613887787703721467290056109612416500723969475 26445568102617050901901253865513813539979895775511757574086986833 64074518730445681820719841702201166570266524813777967344623993932 93909480800354512520847096789097029810546635791616900551118361721 12370102755128096835127924267439374365407557908523215282389147032 54826699835469813270485047312537484671640587315846372293743775219 30919151110636060302891053801210700432453234344091491045730452745 75172859772963841367344298660640458329329949910885141352478853302 82030883457744602695149095071192430431002400801175111573813276724 23993901003977181459213885225696947840551858249503309256746821955 91773533957267935725067696739505646910574548660209215253742177023 78180549120737623398405443257773821555196362582726879079185759635 63517551934604469745590932314794448273464353946473231964241544678 87892787337570038897840273022276345683994325647064645420698254698 61927175681138101855212600088931390666921141908672427391534718069 05539543097196693215008232989615841611284047903608519126186940041 9148181529256070945242288453981096126186120281248517273127180106265052507103740722544939206388645711582064320887604116469048600600449486879609685160881138201425415026265502725906768198615546081219351675094244444767345236642177591092485625573838618103052094965009035778380229728114882013133827468401850917263136033005240371426