Every software system I've ever worked with reduces to the transformation of data . This begs the question what is the simpliest form of data from which all other complex data is built? In other words, what is the data equivilent of the Atomic Theory of matter?
If there is such a thing, it would look similar to what the w3c defines in the semantic web. The data atom (datom) is an RDF tuple. A tuple is a simple data structure that can be implemented in any language as an array or a list yet from such simplicity all other data can be expressed. The humble tuple can be a foundation for building universal data representation.
Unification of Data
It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. -Alan Perlis
The graph is a generic data structure that can represent any type of data. Clojure data structures (list, maps, set, vectorss) are all implemented as trees which is a special case of a graph. Game engines represents scene as a graph. The humble tuple can be a foundation to build graphs for anything from immutable data structures, to databases, to game engines. A set of domain independent functions can be used to manipulate databases or game engines to realize the quote by Alan Perlis.
Clojure, with its built-in immutable data structures using trees and a large set of functions to manipulate a small set of datastrucutres, embodies this philosophy. However, it doesn't go far enough. Clojure itself should be built using only primitives for manipulating tuples and graph data. This philosophy should start from the programming language and extend into the entire application stack (databases, distributed computing, visualization). High level domain specific APIs should be built on nothing more than a complete set of data structure transformation API. These data structure transformation API are the axioms of the system and applications are the theorems. A user can use high level theorems or rely directly on the low-level axioms to accomplish a task. Nothing is hidden. The Matrix should be transparent to anyone.
Calling C functions from Gambit Scheme
lib.c int inc (int x){
return x+1;
}
s.scm
(c-declare "extern int inc ();") ;;c functions must be declared
(define inc (c-lambda (int) int "inc")) ;;function implemented in C code
(pp (map inc '(1 2 3 4)))
Compile as follows
% gsc -c s.scm
% gsc -link s.c
% gsc -obj lib.c s.c s_.c
% gcc lib.o s.o s_.o $GAMBIT/lib/libgambit.a -lm -ldl -lutil -lssl -lcrypto
Calling Gambit Scheme functions from C
slib.scm ;;(##start-repl-server "localhost:44555")
(c-define (inc x) (int) int "inc" "extern"
(+ x 1))
(c-define (fib x) (int) int "fib" "extern"
(if (or (= x 0)
(= x 1))
x
(+ (fib (- x 1))
(fib (- x 2)))))
(c-define (say_hello n) (char-string) char-string "say_hello" "extern"
(string-append "Hello " n "!"))
;;copied from $GAMBIT/test/server.scm
(define (catch-all-errors thunk)
(with-exception-catcher
(lambda (exc)
(write-to-string exc))
thunk))
(define (write-to-string obj)
(with-output-to-string
'()
(lambda () (write obj))))
(define (read-from-string str)
(with-input-from-string str read))
; The following "c-define" form will define the function "eval_string"
; which can be called from C just like an ordinary C function. The
; single argument is a character string (C type "char*") and the
; result is also a character string.
(c-define (eval-string str) (char-string) char-string "eval_string" "extern"
(catch-all-errors
(lambda () (write-to-string (eval (read-from-string str))))))
(c-define (start-repl) () void "start_repl" "extern"
(##start-repl-server "localhost:44555")
(pp "read ")
(read)
(pp "done")
)
slib.h
#include "gambit.h"
typedef ___setup_params_struct GAMBIT;
#define SCHEME_LIBRARY_LINKER ___LNK_slib__ //___LNK_slib__ is defined in slib_.c which is generated with gsc -link slib.c
___BEGIN_C_LINKAGE
extern ___mod_or_lnk SCHEME_LIBRARY_LINKER (___global_state);
___END_C_LINKAGE
GAMBIT* setup_gambit(){
GAMBIT* g = malloc(sizeof(GAMBIT));
___setup_params_reset(g);
g->version = ___VERSION;
g->linker = SCHEME_LIBRARY_LINKER;
___setup(g);
return g;
}
void cleanup_gambit(GAMBIT* g){
___cleanup();
free(g);
}
extern char* say_hello(char* name);
extern int inc(int);
extern int fib(int);
extern char* eval_string(char* s);
extern void start_repl();
main.c
#include
#include
#include "slib.h"
int main(int argc, char** argv) {
printf("Hello World from C\n\n");
GAMBIT* g = setup_gambit();
//printf("From Scheme:\n");
/* char* result = eval_string (argv[1]); */
/* printf("%s = %s\n", argv[1], result); */
/* ___release_string (result); */
start_repl();
cleanup_gambit(g);
return 0;
}
Compile as follows
% gsc -c slib.scm
% gsc -link slib.c #___LNK_slib__ symbol used in main.c generated here
% gcc slib.c slib_.c main.c -D___LIBRARY -I$GAMBIT/include $GAMBIT/lib/libgambit.a -lm -ldl -lutil -lssl -lcrypto
% ./a.out
Hello World from C
From Scheme:
say_hello("Sonny")=Hello Sonny!
inc(2)=3
fib(15)=610
eval_string("(+ 1 1)")=2
#or alternatively build object files with gsc -obj
% gsc -c slib.scm
% gsc -link slib.c #___LNK_slib__ symbol used in main.c generated here
% gsc -obj -cc-options -D___LIBRARY slib.c slib_.c # -cc-options -D___LIBRARY necessary to supress generation of main function
% gsc -obj main.c
% gcc slib.o slib_.o main.o -I$GAMBIT/include $GAMBIT/lib/libgambit.a -lm -ldl -lutil -lssl -lcrypto
% ./a.out
Hello World from C
From Scheme:
say_hello("Sonny")=Hello Sonny!
inc(2)=3
fib(15)=610
eval_string("(+ 1 1)")=2