misc/c/List.c
2018-08-05 18:53:07 +02:00

221 lines
3.7 KiB
C

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
# define T double
# define Nil NULL
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define list(...) fromArray((T []){__VA_ARGS__}, NARGS(__VA_ARGS__))
#define lambda(expr, type, args...) ({ type __fn__ (args){ return expr; }__fn__; })
// List datatype
typedef struct listT {
T head;
struct listT* tail;
}* list;
// String type alias
typedef char* string;
// Prototypes
list pure(T x);
list cons(T x, list xs);
list snoc(T x, list xs);
list take(int k, list xs);
list drop(int k, list xs);
T index_(list xs, int k);
T head(list xs);
T last(list xs);
list head_(list xs);
list last_(list xs);
list tail(list xs);
list init(list xs);
int length(list xs);
list map(T (*f)(T), list xs);
string show(list xs);
string show_(list xs);
void putStrLn(string s);
void putStr(string s);
void print(list xs);
list fromArray (T* xs, int n);
T* toArray(list xs);
// Create singleton list
list pure(T x) {
list p = malloc(sizeof (struct listT));
p->head = x;
p->tail = Nil;
return p;
}
// Append an element before the list xs
list cons(T x, list xs) {
list p = malloc(sizeof (struct listT));
p->head = x;
p->tail = xs;
return p;
}
// Reverse of "cons": append after the list
list snoc(T x, list xs) {
list ys = last_(xs);
ys->tail = pure(x);
return xs;
}
// Take the first k elements of xs
list take(int k, list xs) {
if (k == 0)
return xs;
return cons(xs->head, take(k-1, xs->tail));
}
// Remove the first k elements of xs
list drop(int k, list xs) {
if (k == 0)
return xs;
return drop(k-1, xs->tail);
}
// Return the k-th element of the list xs
T index_(list xs, int k) {
if (k == 0)
return xs->head;
return drop(k-1, xs->tail)->head;
}
// Return the first element (head) of xs
T head(list xs) {
return xs->head;
}
// Return last element of the list
T last(list xs) {
return last_(xs)->head;
}
list last_(list xs) {
if (xs->tail == Nil)
return xs;
return last_(xs->tail);
}
// Return every element of xs but the last one
list init(list xs) {
if (xs->tail->tail == Nil)
return xs;
return init(xs->tail);
}
// Return xs "tail": everything after its first element
list tail(list xs) {
return xs->tail;
}
// Compute the length of a list
int length(list xs) {
if (xs->tail == Nil)
return 1;
return 1 + length(xs->tail);
}
// Apply the function f on every element of xs
list map(T (*f)(T), list xs) {
if (xs->tail == Nil)
return pure((*f)(xs->head));
return cons((*f)(xs->head), map(f, xs->tail));
}
// Convert a C array (given its size) into a list
list fromArray (T* xs, int n) {
if (n == 1)
return pure(*xs);
return cons(*xs, fromArray(xs+1, n-1));
}
// Convert a list into a standard C array
T* toArray(list xs) {
int n = length(xs);
T x, *p = malloc(n * sizeof(T));
for (int i=0; i<n; i++) {
x = head(xs);
xs = tail(xs);
*(p+i) = x;
}
return p;
}
// Create a string representation of a list
string show(list xs) {
string rep = malloc(2 + 2*length(xs) * sizeof(T));
sprintf(rep, "[%s]", show_(xs));
return rep;
}
string show_(list xs) {
string rep = malloc(2*length(xs) * sizeof(T));
sprintf(rep, "%f", xs->head);
if (xs->tail == Nil)
return rep;
strcat(rep, ",");
return strcat(rep, show_(xs->tail));
}
// Print a string to stdout
void putStrLn(string s) {
printf("%s\n", s);
}
// Same as putStrLn without a terminating newline
void putStr(string s) {
printf("%s", s);
}
// Print a list to stdout
void print(list xs) {
putStrLn(show(xs));
}
int main() {
list x = list(1, 2, 3, 4);
float (*f)(float) = lambda(sin(2*x)/x, float, float x);
print(map(f, x));
}