Skip to content
tomahawkins edited this page Apr 18, 2011 · 12 revisions

ImProve programs can only simply read and write variables. Since ImProve has no other notion of IO, a classic "Hello World!" example is not possible. Instead we will present a trivial program that adds two numbers together and then show how to generate C code and integrate it with a larger C program.

To start, create a new Haskell file (Adder.hs) and import the ImProve language:

module Main (main) where

import Language.ImProve

Next declare the variables used for the IO:

-- The 'input' function declares a new primary input variable.
a :: E Float
a = input float ["a"] 

b :: E Float
b = input float ["b"]

-- The 'global' function declares a new global variable, which can
-- either be for internal state or as a primary output.
x :: V Float
x = global float ["x"] 0 

Now create an ImProve program that assigns x = a + b:

adder :: Stmt ()
adder = do
  x <== a + b

Lastly, call the code function to generate C code:

main :: IO ()
main = code C "adder" adder

To compile, run the Haskell program (Adder.hs):

$ runhaskell Adder.hs

This results in two files: adder.h and adder.c. First adder.h:

/* Generated by ImProve. */

#ifdef __cplusplus
extern "C" {
#endif

extern struct {  /* adder_variables */
	float a                        ;  /* input */
	float b                        ;  /* input */
	float x                        ;
} adder_variables;

void adder(void);

#ifdef __cplusplus
}
#endif

And adder.c:

/* Generated by ImProve. */

#include <assert.h>

struct {  /* adder_variables */
	float a                        ;  /* input */
	float b                        ;  /* input */
	float x                        ;
} adder_variables =
	{   0.0              /* a */
	,   0.0              /* b */
	,   0.0              /* x */
	}  /* adder_variables */
;

void adder()
{
	adder_variables.x = (adder_variables.a + adder_variables.b);
}

ImProve generates a hierarchical structure (adder_variables) to hold the variables declared by the ImProve program, and a function (adder) that implements the ImProve program.

Integrating ImProve generated C into a larger program simply involves assigning values to the input variables in the variable structure, calling the generated function, then reading any necessary output variables, again from the variable structure. For example:

#include <stdio.h>

// Include the ImProve generated header.
#include "adder.h"

int main ()
{
        // Assign the ImProve function inputs.
        adder_variables.a = 1.0;
        adder_variables.b = 2.0;

        // Call the ImProve generated function.
        adder();

        // Read the ImProve function outputs.
        printf("%f\n", adder_variables.x);

        return 0;
}

To generate equivalence models in Ada, Simulink, and Modelica, add the following lines to main:

main :: IO ()
main = do
  code C        "adder" adder
  code Ada      "adder" adder
  code Simulink "adder" adder
  code Modelica "adder" adder

Complete File (Adder.hs)

module Main (main) where

import Language.ImProve

-- The 'input' function declares a new primary input variable.
a :: E Float
a = input float ["a"] 

b :: E Float
b = input float ["b"]

-- The 'global' function declares a new global variable, which can
-- either be for internal state or as a primary output.
x :: V Float
x = global float ["x"] 0 

adder :: Stmt ()
adder = do
  x <== a + b

main :: IO ()
main = do
  code C        "adder" adder
  code Ada      "adder" adder
  code Simulink "adder" adder
  code Modelica "adder" adder