├── Makefile ├── README.md ├── closure.c ├── closure.h ├── functional.c ├── functional.h ├── gc.c ├── gc.h ├── list.c ├── list.h └── main.c /Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell ls *.c) 2 | OBJS = $(SRCS:.c=.o) 3 | CFLAGS = -std=c99 -Wall 4 | 5 | test: $(OBJS) 6 | $(CC) $(LDFLAGS) $(OBJS) -o $@ 7 | 8 | %.o: %.c %.h 9 | $(CC) $(CFLAGS) -c $*.c -o $*.o 10 | 11 | .PHONY: all clean 12 | 13 | all: test 14 | 15 | clean: 16 | rm -f *.o test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | functionalC 2 | =========== 3 | 4 | Not because it is good, but because we can... 5 | 6 | (Current blog: https://charlescary.com/) 7 | 8 | e.g. Don't you always wish that you could write like this when you are programming in C? 9 | 10 | ```c 11 | int 12 | main(int argc, char **argv) { 13 | //yep, added first version of garbage collector 14 | gc_init(); //initialize the garbage collector 15 | 16 | iter(map(range(0, 10), dbl,NULL), printint, NULL); 17 | iter(filter(range(0, 10), odd, NULL), printint, NULL); 18 | 19 | //Darker magic? Not really... 20 | closure *addtwo = bind(NULL, add, liftint(2)); 21 | closure *addten = bind(NULL, add, liftint(10)); 22 | 23 | printf("%d\n", *(int *)call(addtwo, liftint(3))); 24 | printf("%d\n", *(int *)call(addten, liftint(3))); 25 | 26 | //all together now, with pseudo types everywhere woopie!!! 27 | list *vars = liftlist(range(0, 10), sizeof(int)); 28 | list *res = lmap(vars, addtwo); 29 | iter(res, printint, NULL); 30 | 31 | gc_print(); //show eveything currently in the garbage collector 32 | 33 | gc_collect(); //you can guess what this does 34 | 35 | gc_print(); //anything left? 36 | 37 | //NOTE: The garbage collector is a work in progress. 38 | //we're not tracking everything yet and 39 | //the collector doesn't necessarily avoid double frees! 40 | //BEWARE!!! 41 | 42 | exit(0); 43 | } 44 | 45 | ``` 46 | 47 | No? Neither did I. This is horrible. 48 | 49 | Functional C Programming Doc 50 | ============================ 51 | 52 | # The Basics 53 | 54 | Our basic type is the list. 55 | 56 | ```c 57 | struct list { 58 | void *val; 59 | list *next; 60 | }; 61 | ``` 62 | 63 | All of our functions use this type. There are helper functions to work with lists like newitem, copyitem, and append. Look at the code. 64 | 65 | Some standard functional programming functions: 66 | 67 | ```c 68 | //iterates through a list calling fn 69 | void 70 | iter(list *l, void (*fn)(void *, void *), void *args) 71 | ``` 72 | ```c 73 | //yeah, it's map 74 | list * 75 | map(list *l, void *(*fn)(void *, void *), void *args) 76 | ``` 77 | 78 | ```c 79 | //lifted map is so that you can map closures; maybe we'll unify the type system later... 80 | list * 81 | lmap(list *l, closure *cl) 82 | ``` 83 | 84 | ```c 85 | //yup, and filter too 86 | list * 87 | filter(list *l, bool (*fn)(void *, void *), void *args) 88 | ``` 89 | 90 | ```c 91 | //for fun 92 | list * 93 | range(int start, int end) 94 | ``` 95 | 96 | # Closures 97 | 98 | Closures are built around two types: a closure and an environment variable 99 | 100 | ```c 101 | struct closure { 102 | void *(*fn)(list *); 103 | list *env; 104 | }; 105 | 106 | struct envobj { 107 | void *val; 108 | ssize_t size; 109 | }; 110 | ``` 111 | 112 | A closure is a function that is bound to an environment. To bind an environment variable to a closure, use the bind function. 113 | 114 | ```c 115 | closure * 116 | bind(closure *c, void *(*fn)(list *), envobj *env); 117 | ``` 118 | 119 | To call this closed function, we use the call function: 120 | 121 | ```c 122 | void * 123 | call(closure *c, envobj *env); 124 | ``` 125 | 126 | To make environment variables, we need to lift our types into the environment. 127 | 128 | ```c 129 | //returns a lifted integer 130 | envobj * 131 | liftint(int a); 132 | ``` 133 | 134 | ```c 135 | //this transforms a list into an environment 136 | list * 137 | liftlist(list *l, ssize_t s) 138 | ``` 139 | 140 | # Garbage Collector 141 | 142 | The garbage collector is defined is gc.c . It maintains a linked list of every reference you register with it. On a call to gc_collect, it frees the references based on the handlers that you have specified. 143 | 144 | ```c 145 | //this starts the garbage collector. You should call this before you do anything else 146 | void gc_init(void); 147 | ``` 148 | 149 | Lists, environment objects, and closures are automatically registered with the garbage collector. 150 | 151 | ```c 152 | //supported types 153 | enum TYPE { 154 | LIST, 155 | ENVOBJ, 156 | CLOSURE, 157 | STANDARD //gc's an generic obj 158 | }; 159 | ``` 160 | 161 | To register any pointer: 162 | 163 | ```c 164 | //type = STANDARD with for a generic pointer 165 | void 166 | gc_register(void *obj, TYPE type); 167 | ``` 168 | 169 | To register a new type with the garbage collector, add it to enum TYPE (update gc.h), and then update gc_init to register your handler. 170 | 171 | ```c 172 | void 173 | gc_register_destructor(TYPE, void (*)(void *)); 174 | ``` 175 | A call to gc_collect performs garbage collection: 176 | 177 | ```c 178 | void 179 | gc_collect(void); 180 | ``` 181 | 182 | Other functions: 183 | 184 | ```c 185 | //prints what the garbage collector is tracking 186 | void 187 | gc_print(void); 188 | ``` 189 | 190 | Expirimental / Untested functionality: 191 | 192 | ```c 193 | //tells the garbage collector to mark an object for safe keeping. 194 | //it will now be tracked by the collector, but not freed until it is unmarked. 195 | void 196 | gc_mark(void *obj); 197 | 198 | //unmarks an object 199 | void 200 | gc_unmark(void *obj); 201 | 202 | //tells the garbage collector to stop tracking an object 203 | void 204 | gc_remove(void *obj); 205 | ``` 206 | 207 | License 208 | ======= 209 | 210 | Copyright (c) 2013 Charles Cary 211 | 212 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 213 | 214 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 215 | 216 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 217 | 218 | -------------------------------------------------------------------------------- /closure.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "list.h" 4 | #include "closure.h" 5 | #include "gc.h" 6 | 7 | envobj * 8 | envitem(void *var, ssize_t size) { 9 | envobj *env = malloc(sizeof(envobj)); 10 | env->val = var; 11 | env->size = size; 12 | gc_register((void *)env, ENVOBJ); 13 | return env; 14 | } 15 | 16 | void * 17 | unbox(list *l) { 18 | envobj *env = (envobj *)l->val; 19 | return env->val; 20 | } 21 | 22 | closure * 23 | bind(closure *c, void *(*fn)(list *), envobj *env) { 24 | closure *cl; 25 | if (c == NULL) { 26 | cl = malloc(sizeof(closure)); 27 | if (cl == NULL) { 28 | exit(1); 29 | } 30 | cl->env = NULL; 31 | cl->fn = fn; 32 | gc_register((void *)cl, CLOSURE); 33 | } 34 | else { 35 | cl = c; 36 | } 37 | cl->env = append(cl->env, (void *)env); 38 | return cl; 39 | } 40 | 41 | void * 42 | call(closure *c, envobj *env) { 43 | list *copylist = copy(c->env); 44 | copylist = append(copylist, (void *)env); 45 | return c->fn(copylist); 46 | } 47 | 48 | //helper functions (syntactic sugar...erm...i guess...) 49 | //these make using closures easier 50 | envobj * 51 | liftint(int a) { 52 | int *v = malloc(sizeof(int)); 53 | *v = a; 54 | gc_register((void *)v, STANDARD); 55 | envobj *o = envitem((void *)v, sizeof(int)); 56 | return o; 57 | } 58 | 59 | void 60 | envobj_free(void *_obj) { 61 | envobj *obj = _obj; 62 | free(obj); 63 | } 64 | 65 | list * 66 | liftlist(list *l, ssize_t s) { 67 | list *o = NULL; 68 | list *curr; 69 | 70 | for (curr = l; curr != NULL; curr = curr->next) { 71 | envobj *lifted = envitem(curr->val, s); 72 | o = append(o, (void *)lifted); 73 | } 74 | return o; 75 | } 76 | 77 | void 78 | closure_free(void *_c) { 79 | closure *c = _c; 80 | free(c); 81 | } 82 | -------------------------------------------------------------------------------- /closure.h: -------------------------------------------------------------------------------- 1 | #ifndef CLOSURE_H 2 | #define CLOSURE_H 3 | #include 4 | #include "list.h" 5 | 6 | typedef struct closure closure; 7 | 8 | struct closure { 9 | void *(*fn)(list *); 10 | list *env; 11 | }; 12 | 13 | typedef struct envobj envobj; 14 | 15 | struct envobj { 16 | void *val; 17 | ssize_t size; 18 | }; 19 | 20 | envobj *envitem(void *var, ssize_t s); 21 | void *unbox(list *l); 22 | closure *bind(closure *c, void *(*fn)(list *), envobj *env); 23 | void *call(closure *c, envobj *env); 24 | envobj *liftint(int a); 25 | list *liftlist(list *l, ssize_t s); 26 | void envobj_free(void *); 27 | void closure_free(void *); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /functional.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "list.h" 4 | #include "functional.h" 5 | #include "closure.h" 6 | 7 | //some standard functional programming functions 8 | void 9 | iter(list *l, void (*fn)(void *, void *), void *args) { 10 | list *curr; 11 | for (curr = l; curr != NULL; curr = curr->next) { 12 | (*fn)(curr->val, args); 13 | } 14 | } 15 | 16 | list * 17 | map(list *l, void *(*fn)(void *, void *), void *args) { 18 | list *o = NULL; 19 | list *curr; 20 | for (curr = l; curr != NULL; curr = curr->next) { 21 | o = append(o, (*fn)(curr->val, args)); 22 | } 23 | return o; 24 | } 25 | 26 | list * 27 | lmap(list *l, closure *cl) { 28 | list *o = NULL; 29 | list *curr; 30 | for (curr = l; curr != NULL; curr = curr->next) { 31 | o = append(o, call(cl, (envobj *)curr->val)); 32 | } 33 | return o; 34 | } 35 | 36 | list * 37 | filter(list *l, bool (*fn)(void *, void *), void *args) { 38 | list *o = NULL; 39 | list *curr; 40 | for (curr = l; curr != NULL; curr = curr->next) { 41 | if ((*fn)(curr->val, args)) { 42 | o = append(o, copyitem(curr->val)); 43 | } 44 | } 45 | return o; 46 | } 47 | 48 | //not lazy 49 | list * 50 | range(int start, int end) { 51 | list *o = NULL; 52 | for (int i = start; i <= end; ++i) { 53 | int *aloc = malloc(sizeof(int)); 54 | *aloc = i; 55 | o = append(o, (void *)aloc); 56 | } 57 | return o; 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /functional.h: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTIONAL_H 2 | #define FUNCTIONAL_H 3 | #include "list.h" 4 | #include "closure.h" 5 | 6 | void iter(list *l, void (*fn)(void *, void *), void *args); 7 | 8 | list *map(list *l, void *(*fn)(void *, void *), void *args); 9 | //map for lifted types 10 | list *lmap(list *l, closure *cl); 11 | 12 | list *filter(list *l, bool (*fn)(void *, void *), void *args); 13 | 14 | list *range(int start, int end); 15 | 16 | #endif 17 | 18 | -------------------------------------------------------------------------------- /gc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "gc.h" 4 | #include "closure.h" 5 | #include "list.h" 6 | 7 | typedef struct ref ref; 8 | struct ref { 9 | void *ptr; //pointer to the obj 10 | TYPE type; //obj type 11 | ref *next; //refs are stored as a list; 12 | }; 13 | 14 | typedef struct gc gc; 15 | struct gc { 16 | ref *marked; //these will not be freed unless unmarked 17 | ref *last_marked; 18 | ref *unmarked; //these will be freed when gc_collect is called 19 | ref *last_unmarked; //we want append to be O(1) 20 | void (*destructor_table[TYPE_COUNT])(void *); 21 | }; 22 | 23 | //this IS the garbage collector 24 | static gc _gc; 25 | 26 | //private functions 27 | void gc_register_destructor(TYPE, void (*)(void *)); 28 | ref *refitem(void *, TYPE); 29 | void append_unmarked(ref *unmarked); 30 | void append_marked(ref *marked); 31 | ref *remove_unmarked(void *obj); 32 | ref *remove_marked(void *obj); 33 | void standard_free(void *ptr); 34 | 35 | void 36 | gc_register_destructor(TYPE type, void (*destructor)(void *)) { 37 | _gc.destructor_table[type] = destructor; 38 | } 39 | 40 | ref * 41 | refitem(void *ptr, TYPE type) { 42 | ref *o = malloc(sizeof(ref)); 43 | o->ptr = ptr; 44 | o->type = type; 45 | o->next = NULL; 46 | return o; 47 | } 48 | 49 | void 50 | append_unmarked(ref *unmarked) { 51 | if (_gc.unmarked == NULL) { 52 | _gc.unmarked = unmarked; 53 | _gc.last_unmarked = _gc.unmarked; 54 | } 55 | else { 56 | _gc.last_unmarked->next = unmarked; 57 | _gc.last_unmarked = unmarked; 58 | } 59 | } 60 | 61 | ref * 62 | remove_unmarked(void *obj) { 63 | ref *curr = _gc.unmarked; 64 | if (curr == NULL) { 65 | return NULL; 66 | } 67 | if (curr->ptr == obj) { 68 | _gc.unmarked = curr->next; 69 | curr->next = NULL; 70 | return curr; 71 | } 72 | if (_gc.last_unmarked->ptr == obj) { 73 | for (; curr->next->ptr != obj; curr = curr->next) 74 | ; 75 | ref *o = _gc.last_unmarked; 76 | o->next = NULL; 77 | _gc.last_unmarked = curr; 78 | curr->next = NULL; 79 | return o; 80 | } 81 | for (; curr->next != NULL; curr = curr->next) { 82 | if (curr->next->ptr == obj) { 83 | ref *o = curr->next; 84 | curr->next = o->next; 85 | o->next = NULL; 86 | return o; 87 | } 88 | } 89 | return NULL; 90 | } 91 | 92 | ref * 93 | remove_marked(void *obj) { 94 | ref *curr = _gc.marked; 95 | if (curr == NULL) { 96 | return NULL; 97 | } 98 | if (curr->ptr == obj) { 99 | _gc.marked = curr->next; 100 | curr->next = NULL; 101 | return curr; 102 | } 103 | if (_gc.last_marked->ptr == obj) { 104 | for (; curr->next->ptr != obj; curr = curr->next) 105 | ; 106 | ref *o = _gc.last_marked; 107 | o->next = NULL; 108 | _gc.last_marked = curr; 109 | curr->next = NULL; 110 | return o; 111 | } 112 | for (; curr->next != NULL; curr = curr->next) { 113 | if (curr->next->ptr == obj) { 114 | ref *o = curr->next; 115 | curr->next = o->next; 116 | o->next = NULL; 117 | return o; 118 | } 119 | } 120 | return NULL; 121 | } 122 | 123 | void 124 | append_marked(ref *marked) { 125 | if (_gc.marked == NULL) { 126 | _gc.marked = marked; 127 | _gc.last_marked = _gc.marked; 128 | } 129 | else { 130 | _gc.last_marked->next = marked; 131 | _gc.last_marked = marked; 132 | } 133 | } 134 | 135 | void 136 | standard_free(void *ptr) { 137 | free(ptr); 138 | } 139 | 140 | //public functions 141 | void 142 | gc_init(void) { 143 | //register destructors here 144 | //all of these are basically just standard free 145 | //just showing that one could register other destructors 146 | gc_register_destructor(ENVOBJ, envobj_free); 147 | gc_register_destructor(CLOSURE, closure_free); 148 | gc_register_destructor(LIST, list_free); 149 | gc_register_destructor(STANDARD, standard_free); 150 | //don't change these 151 | _gc.marked = NULL; 152 | _gc.unmarked = NULL; 153 | _gc.last_unmarked = NULL; 154 | _gc.last_marked = NULL; 155 | } 156 | 157 | void 158 | gc_remove(void *obj) { 159 | ref *r1 = remove_unmarked(obj); 160 | if (r1 != NULL) { 161 | free(r1); 162 | } 163 | ref *r2 = remove_marked(obj); 164 | if (r2 != NULL) { 165 | free(r2); 166 | } 167 | } 168 | 169 | void 170 | gc_mark(void *obj) { 171 | ref *r = remove_unmarked(obj); 172 | append_marked(r); 173 | } 174 | 175 | void 176 | gc_unmark(void *obj) { 177 | ref *r = remove_marked(obj); 178 | append_unmarked(r); 179 | } 180 | 181 | //don't register objs twice; boy that could go poorly 182 | void 183 | gc_register(void *obj, TYPE type) { 184 | ref *n = refitem(obj, type); 185 | append_unmarked(n); 186 | } 187 | 188 | void 189 | gc_collect(void) { 190 | ref *curr = _gc.unmarked; 191 | while (curr != NULL) { 192 | ref *next = curr->next; 193 | (*(_gc.destructor_table[curr->type]))(curr->ptr); 194 | free(curr); 195 | curr = next; 196 | } 197 | _gc.unmarked = NULL; 198 | } 199 | 200 | //displays everything inside the garbage collector 201 | //for debugging purposes 202 | void 203 | gc_print(void) { 204 | ref *curr; 205 | printf("TO BE COLLECTED (UNMARKED):\n"); 206 | for (curr = _gc.unmarked; curr != NULL; curr = curr->next) { 207 | switch(curr->type) { 208 | case LIST: 209 | printf("LIST at %p\n", curr->ptr); 210 | break; 211 | case STANDARD: 212 | printf("STANDARD at %p\n", curr->ptr); 213 | break; 214 | case ENVOBJ: 215 | printf("ENVOBJ at %p\n", curr->ptr); 216 | break; 217 | case CLOSURE: 218 | printf("CLOSURE at %p\n", curr->ptr); 219 | break; 220 | } 221 | } 222 | printf("MARKED FOR SAFE KEEPING:\n"); 223 | for (curr = _gc.marked; curr != NULL; curr = curr->next) { 224 | switch(curr->type) { 225 | case LIST: 226 | printf("LIST at %p\n", curr->ptr); 227 | break; 228 | case STANDARD: 229 | printf("STANDARD at %p\n", curr->ptr); 230 | break; 231 | case ENVOBJ: 232 | printf("ENVOBJ at %p\n", curr->ptr); 233 | break; 234 | case CLOSURE: 235 | printf("CLOSURE at %p\n", curr->ptr); 236 | break; 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /gc.h: -------------------------------------------------------------------------------- 1 | #ifndef GC_H 2 | #define GC_H 3 | typedef enum TYPE TYPE; 4 | 5 | enum TYPE { 6 | LIST, 7 | ENVOBJ, 8 | CLOSURE, 9 | STANDARD //gc's an generic obj 10 | }; 11 | 12 | #define TYPE_COUNT 4 13 | 14 | void gc_mark(void *obj); 15 | void gc_unmark(void *obj); 16 | void gc_register(void *obj, TYPE type); 17 | void gc_remove(void *obj); 18 | void gc_init(void); 19 | void gc_collect(void); 20 | void gc_print(void); 21 | #endif 22 | -------------------------------------------------------------------------------- /list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "list.h" 5 | #include "gc.h" 6 | 7 | list * 8 | newitem(void *v) { 9 | list *o = malloc(sizeof(list)); 10 | if (o == NULL) { 11 | exit(1); 12 | } 13 | o->val = v; 14 | o->next = NULL; 15 | gc_register((void *)o, LIST); 16 | return o; 17 | } 18 | 19 | list * 20 | copyitem(list *i) { 21 | list *o = malloc(sizeof(list)); 22 | if (o == NULL) { 23 | exit(1); 24 | } 25 | o->val = i->val; 26 | o->next = NULL; 27 | return o; 28 | } 29 | 30 | list * 31 | append(list *l, void *v) { 32 | list *ni = newitem(v); 33 | if (l == NULL) { 34 | return ni; 35 | } 36 | list *curr; 37 | for (curr = l; curr->next != NULL; curr = curr->next) 38 | ; 39 | curr->next = ni; 40 | return l; 41 | } 42 | 43 | list * 44 | concat(list *h, list *t) { 45 | list *curr; 46 | for (curr = h; curr->next != NULL; curr = curr->next) 47 | ; 48 | curr->next = t; 49 | return h; 50 | } 51 | 52 | //shallow copy 53 | list * 54 | copy(list *l) { 55 | list *o = NULL; 56 | list *curr; 57 | for (curr = l; curr != NULL; curr = curr->next) { 58 | o = append(o, curr->val); 59 | } 60 | return o; 61 | } 62 | 63 | //objs flag set to true will also free the objects in the list 64 | void 65 | list_free(void *_l) { 66 | list *l = _l; 67 | free(l); 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H 2 | #define LIST_H 3 | #include 4 | 5 | //our list type that we'll use throughout 6 | //along with the helper functions: newitem and append 7 | //this is boring, go down to main 8 | typedef struct list list; 9 | 10 | struct list { 11 | void *val; 12 | list *next; 13 | }; 14 | 15 | list *newitem(void *v); 16 | list *copyitem(list *i); 17 | list *append(list *l, void *v); 18 | list *concat(list *h, list *t); 19 | list *copy(list *h); 20 | void list_free(void *); 21 | 22 | 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "list.h" 4 | #include "functional.h" 5 | #include "closure.h" 6 | #include "gc.h" 7 | 8 | // a function to play with iter 9 | void 10 | printint(void *v, void *args) { 11 | printf("%d\n", (int)(*(int *)v)); 12 | } 13 | 14 | //returns true if int v is odd, false otherwise 15 | bool 16 | odd(void *v, void *args) { 17 | return (bool)(*((int *)v) % 2); 18 | } 19 | 20 | //returns twice int v 21 | //boy is this terrible 22 | void * 23 | dbl(void *v, void *args) { 24 | int *o = malloc(sizeof(int)); 25 | *o = *((int *)v) * 2; 26 | return o; 27 | } 28 | 29 | //we'll use this to play with closures 30 | void * 31 | add(list *l) { 32 | int *a = unbox(l); 33 | int *b = unbox(l->next); 34 | int *o = malloc(sizeof(int)); 35 | *o = *a + *b; 36 | return o; 37 | } 38 | 39 | int 40 | main(int argc, char **argv) { 41 | 42 | gc_init(); //initialize the garbage collector 43 | 44 | iter(map(range(0, 10), dbl,NULL), printint, NULL); 45 | iter(filter(range(0, 10), odd, NULL), printint, NULL); 46 | 47 | //Darker magic? Not really... 48 | closure *addtwo = bind(NULL, add, liftint(2)); 49 | closure *addten = bind(NULL, add, liftint(10)); 50 | 51 | printf("%d\n", *(int *)call(addtwo, liftint(3))); 52 | printf("%d\n", *(int *)call(addten, liftint(3))); 53 | 54 | //all together now, with pseudo types everywhere woopie!!! 55 | list *vars = liftlist(range(0, 10), sizeof(int)); 56 | list *res = lmap(vars, addtwo); 57 | iter(res, printint, NULL); 58 | 59 | gc_print(); //show eveything currently in the garbage collector 60 | 61 | gc_collect(); //you can guess what this does 62 | 63 | gc_print(); //anything left? 64 | 65 | //NOTE: The garbage collector is a work in progress. 66 | //wer're not tracking everything yet and 67 | //the collector doesn't necessarily avoid double frees! 68 | //BEWARE!!! 69 | 70 | exit(0); 71 | } 72 | --------------------------------------------------------------------------------