[pure-lang-svn] SF.net SVN: pure-lang: [309] pure/trunk
Status: Beta
Brought to you by:
agraef
From: <ag...@us...> - 2008-06-24 23:46:14
|
Revision: 309 http://pure-lang.svn.sourceforge.net/pure-lang/?rev=309&view=rev Author: agraef Date: 2008-06-24 16:46:23 -0700 (Tue, 24 Jun 2008) Log Message: ----------- Add sort.c example. Modified Paths: -------------- pure/trunk/ChangeLog Added Paths: ----------- pure/trunk/examples/sort.c Modified: pure/trunk/ChangeLog =================================================================== --- pure/trunk/ChangeLog 2008-06-24 22:45:02 UTC (rev 308) +++ pure/trunk/ChangeLog 2008-06-24 23:46:23 UTC (rev 309) @@ -1,3 +1,10 @@ +2008-06-25 Albert Graef <Dr....@t-...> + + * examples/sort.c: Add another example for the runtime API. + This one shows how to implement a C function in a module to be + loaded by the Pure interpreter, which in turn calls other C and + Pure functions. + 2008-06-24 Albert Graef <Dr....@t-...> * configure.ac: Bump version number. @@ -6,6 +13,8 @@ completion. * examples/poor.c: Add an example for the new public runtime API. + Shows how to interface to the Pure interpreter in a standalone C + application. * interpreter.cc/h, runtime.cc/h, lib/strings.pure: Add error reporting to the eval() routine. Added: pure/trunk/examples/sort.c =================================================================== --- pure/trunk/examples/sort.c (rev 0) +++ pure/trunk/examples/sort.c 2008-06-24 23:46:23 UTC (rev 309) @@ -0,0 +1,110 @@ + +/* Sort a Pure list using the C qsort() function. 2008-06-25 AG */ + +/* Another example using the runtime API. It implements an external function + 'sort' which can be loaded inside the Pure interpreter. The function, to be + invoked as 'sort p xs', calls the qsort() routine from the C library to + sort a Pure list xs using a given Pure predicate p, which compares two + elements x and y and returns a truth value indicating whether x is less + than y. The example illustrates how we can program a C function to be + called from Pure which in turn calls other Pure functions, and takes + generic pure_expr* values as arguments and returns them as results. */ + +/* To compile (Linux): 'gcc -shared -o sort.so sort.c -lpure'. This will + create a dynamic library ready to be loaded by the Pure interpreter. + (Replace .so with .dylib or .dll on OSX and Windows, respectively. On OSX, + you also have to replace -shared with -dynamiclib. On Windows you might + wish to add the '-Wl,--enable-auto-import' linker option.) + + I suggest that you also set up your LD_LIBRARY_PATH environment variable + (DYLD_LIBRARY_PATH on OSX) so that the dynamic loader finds sort.so without + further ado. Something like 'export LD_LIBRARY_PATH=.' should do the trick. + Windows doesn't need this since it always searches the current directory + for dlls. + + Now start the interpreter and enter the following to "dlopen" sort.so and + declare the sort function: + + > using "lib:sort"; + > extern expr* sort(expr* p, expr *xs); + + The sort function is now ready to be called as 'sort p xs', e.g.: + + > sort (<) (1..10); + [1,2,3,4,5,6,7,8,9,10] + > sort (>) (1..10); + [10,9,8,7,6,5,4,3,2,1] + + Have some fun with random lists, comparing our sort function with the one + from hello.pure. (The rand function is also declared in hello.pure; it is + just the rand() function from the C library.) + + > run hello.pure + Hello, world! + > let xs = [rand; i = 1..100000]; + > stats + > #sort (<) xs; + 100000 + 1.05s + > #qsort (<) xs; + 100000 + 14.05s + + The above results are for my Athlon 2500+. YMMV, but most likely you'll get + similar results indicating that the C implementation is much faster. That's + because the quicksort algorithm in hello.pure juggles around with lists, + whereas the C quicksort routine uses vectors and sorts the elements + in-place. */ + +#include <stdlib.h> +#include <pure/runtime.h> + +/* Set up a C callback which in turn invokes a Pure predicate to perform the + comparison of list elements. */ + +static pure_expr* cmp_p; +static int cmp(const void *xp, const void *yp) +{ + pure_expr *x = *(pure_expr**)xp, *y = *(pure_expr**)yp; + /* We use pure_appl to invoke the Pure predicate stored in cmp_p on the list + elements x and y passed by the qsort() routine. */ + pure_expr *p = pure_appl(cmp_p, 2, x, y); + int res = pure_is_int(p, &res) && res; /* x<y? */ + pure_freenew(p); /* collect temporary */ + if (res) + res = -1; + else { + /* Invoke cmp_p another time to perform the reverse comparison. */ + p = pure_appl(cmp_p, 2, y, x); + res = pure_is_int(p, &res) && res; /* y<x? */ + pure_freenew(p); /* collect temporary */ + /* Note that if both tests failed then the elements are either equal or + incomparable, in which case res==0. */ + } + return res; +} + +pure_expr *sort(pure_expr *p, pure_expr *xs) +{ + size_t size; + pure_expr **elems; + /* Deconstruct the list argument which is passed as a pure_expr* value. + This yields a vector of pure_expr* elements which can be passed to the + qsort() routine. */ + if (pure_is_listv(xs, &size, &elems)) { + pure_expr *ys; + /* Invoke qsort() to sort the elems vector. */ + cmp_p = p; + qsort(elems, size, sizeof(pure_expr*), cmp); + /* Construct a new list value from the sorted vector, to be returned as + the function result. */ + ys = pure_listv(size, elems); + /* The elems vector returned by pure_is_listv is malloc'ed, free it now so + that we don't leak memory. */ + free(elems); + return ys; + } else + /* The xs argument wasn't a proper list value, return a NULL pointer to + indicate failure. This will make the 'sort p xs' call a normal form. */ + return 0; +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |