ePolyglot: Examination and development of multilanguage programming using Eiffel, Python, and Haskell | ||
---|---|---|
Prev | Chapter 13. Haskell from Eiffel | Next |
Because of the additional necessary hand-edited files, the regression_test application has more source code than our other sample applications:
Example 13-9. Source code for the regression_test sample program
First, the Regression.hs file, containing the Haskell functions to be exported:
module Regression where import Int average :: [Double] -> Double average [] = 0 average x = sum x / fromInt(length x) square :: Num a => a -> a square x = x^2 dcount :: [Double] -> Double dcount xs = fromInt( length xs ) mult_terms :: [Double] -> [Double] -> [Double] mult_terms [] [] = [] mult_terms (x:xs) (y:ys) = [x*y] ++ mult_terms xs ys beta_1 :: [Double] -> [Double] -> Double beta_1 xs ys = top / bottom where top = sum( mult_terms xs ys ) - dcount xs * average xs * average ys bottom = sum ( map square xs) - dcount xs * square ( average xs ) beta_0 :: [Double] -> [Double] -> Double beta_0 xs ys = average ys - beta_1 xs ys * average xs |
...and the IDL file for exporting those functions, Regression_proxy.idl
module Regression { [pure]double beta_0( [in, size_is(len_xs)]double* xs, [in]int len_xs, [in, size_is(len_ys)]double* ys, [in]int len_ys ); [pure]double beta_1( [in, size_is(len_xs)]double* xs, [in]int len_xs, [in, size_is(len_ys)]double* ys, [in]int len_ys ); } |
The interface file for SWIG, Regression.i...
%module regression %{ #include "Regression.h" %} double beta_0 ( /*[in, size_is(len_xs)]*/double* xs , /*[in]*/int len_xs , /*[in, size_is(len_ys)]*/double* ys , /*[in]*/int len_ys ); /*[pure]*/ double beta_1 ( /*[in, size_is(len_xs)]*/double* xs , /*[in]*/int len_xs , /*[in, size_is(len_ys)]*/double* ys , /*[in]*/int len_ys ); extern void startupHaskell( int argc, char argv[][] ); extern void start_haskell( void ); |
...and the wrapper function to start the Haskell runtime, wrap_start_haskell.c:
extern void startupHaskell( int argc, char**argv ); void start_haskell( void ) { char * argv[] = { "bob", "tim" }; startupHaskell( 1, argv ); } |
Finally, the actual Eiffel test program:
class REGRESSION_TEST inherit REGRESSION_WRAPPER creation make feature eol : ARRAY[DOUBLE] is once create Result.from_collection( << 130.0, 650.0, 99.0, 150.0, 128.0, 302.0, 95.0, 945.0, 368.0, 961.0 >> ) end enc : ARRAY[DOUBLE] is once create Result.from_collection( << 163.0, 765.0, 141.0, 166.0, 137.0, 355.0, 136.0, 1206.0, 433.0, 1130.0 >> ) end anc : ARRAY[DOUBLE] is once create Result.from_collection( << 186.0, 699.0, 132.0, 272.0, 291.0, 331.0, 199.0, 1890.0, 788.0, 1601.0 >> ) end make is local do start_haskell io.put_string( "%N%NEst obj vs actual new/changed: Beta-0: " ) io.put_double( beta_0( eol, eol.count, anc, anc.count ) ) io.put_string( " Beta-1: " ) io.put_double( beta_1( eol, eol.count, anc, anc.count ) ) io.put_new_line io.put_string( "Est new/changed vs actual new/changed: Beta-0: " ) io.put_double( beta_0( enc, enc.count, anc, anc.count ) ) io.put_string( " Beta-1: " ) io.put_double( beta_1( enc, enc.count, anc, anc.count ) ) io.put_new_line end end |
The program runs, simulating one of the runs of PSP program 4a, with static values for the arrays of numbers rather than reading them from a file. It produces the output shown below:
Example 13-10. Output from the regression_test application
[vputz@yak_prime regression]$ ./regression_test Est obj vs actual new/changed: Beta-0: -22.552533 Beta-1: 1.727932 Est new/changed vs actual new/changed: Beta-0: -23.923888 Beta-1: 1.430967 [vputz@yak_prime regression]$ |
The final program is rather huge--1.4 megabytes before stripping and 590k after, but it does work, and works rather well. With this toy example, we haven't done much to convince anyone that multilanguage programming will save program space or run-time, but the reduction in code size of the simple regression calculation should indicate that the volume of source code generated for a large, complex computing application could be significantly reduced, gaining simplicity and ease-of-understanding from the use of a functional language as the computational core. All that remains to make our multilanguage experiment complete is the successful merging of all three languages into a single program...