ePolyglot: Examination and development of multilanguage programming using Eiffel, Python, and Haskell | ||
---|---|---|
Prev | Chapter 14. All three: Eiffel, Python, and Haskell together | Next |
The tri-language program required few changes from its bi-lingual counterpart in the previous chapter. In fact, none of the Haskell interface files were changed, so they are not duplicated here. The only changes were a routine to shuffle values from Python lists into Eiffel arrays of doubles, and of course the Python script to load the values from disk. Values were provided in the following format:
Example 14-1. Data file for regression_test
130,186 650, 699 99, 132 150, 272 128, 291 302, 331 95, 199 945, 1890 368, 788 961, 1601 |
These values were loaded and parsed by the Python function paired_arrays_from_file, located in the loader.py module:
Example 14-2. The loader.py module
#simple module to load numbers from a file import re def paired_arrays_from_file( filename ) : a_series = [] b_series = [] f = open(filename, "r" ) lines = f.readlines() regex = re.compile( r"^\s*(\S*?),\s*(\S*?)\s*$" ) for line in lines : matches = regex.match( line ) if len( matches.group( 1 ) ) > 0 and len( matches.group( 2 ) ) > 0 : a_series.append( float( matches.group( 1 ) ) ) b_series.append( float( matches.group( 2 ) ) ) return( a_series, b_series ); |
The loader.py module and Haskell code were controlled by the overall application regression_test.e:
Example 14-3. The regression_test.e source file
class REGRESSION_TEST inherit REGRESSION_WRAPPER PYTHON_CLIENT creation make feature array_from_python_list( pyobj : PYTHON_OBJECT ) : ARRAY[ DOUBLE ] is local i : INTEGER n : PYTHON_FLOAT pyarr : PYTHON_LIST do create pyarr.make_from_python_object( pyobj ) create Result.with_capacity( pyarr.length, 0 ) from i := pyarr.lower until i > pyarr.upper loop create n.make_from_python_object( pyarr.item( i ) ) Result.add_last( n.to_double ) i := i + 1 end end show_regression( filename : STRING ) is local series_a, series_b : ARRAY[ DOUBLE ] m : LOADER t : PYTHON_TUPLE r : INTEGER do py_initialize r := py_run_simple_string( "import sys" ); r := py_run_simple_string( "sys.path.append( '.' )" ) start_haskell create m.make create t.make_from_python_object( m.paired_arrays_from_file( << filename >> ) ) series_a := array_from_python_list( t.item( 0 ) ) series_b := array_from_python_list( t.item( 1 ) ) io.put_string( "%N%NLinear regression of series: Beta-0: " ) io.put_double( beta_0( series_a, series_a.count, series_b, series_b.count ) ) io.put_string( " Beta-1: " ) io.put_double( beta_1( series_a, series_a.count, series_b, series_b.count ) ) io.put_new_line end make is do if argument_count /= 1 then io.put_string( "Usage : regression_test filename%N%N" ) else show_regression( argument( 1 ) ) end rescue if not py_err_occurred.is_null then py_err_print end end end |
The resultant output is the same as the earlier example program, which indicates that we have done our job correctly:
Example 14-4. Output from the poly_regression version of regression_test
[vputz@yak_prime poly_regression]$ ./regression_test test_1 Linear regression of series: Beta-0: -22.552533 Beta-1: 1.727932 |
At last, we have realized the vision of multilingual programming using Eiffel, Haskell, and Python together in the same executable.