Last active
June 16, 2020 21:06
-
-
Save josephcsible/b02b78a9249b20fbe60a8f65e29d5553 to your computer and use it in GitHub Desktop.
Combinatory logic with C, using raw function pointers as closures
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <inttypes.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
typedef void *(*f)(void *); | |
f make_function_with_state(f code, size_t code_len, void *state, size_t state_len) { | |
f mem = mmap(NULL, code_len + state_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | |
memcpy(mem, code, code_len); | |
memcpy(mem + code_len, state, state_len); | |
mprotect(mem, code_len + state_len, PROT_READ|PROT_EXEC); | |
return mem; | |
} | |
extern void *single_var_helper(void *); | |
extern const size_t single_var_helper_len; | |
__asm__( | |
"single_var_helper:\n" | |
"endbr64\n" | |
"mov %rdi,%rsi\n" | |
"mov single_var_helper_len(%rip), %rdi\n" | |
"jmp *single_var_helper_len+8(%rip)\n" | |
"single_var_helper_len:\n" | |
".8byte .-single_var_helper" | |
); | |
extern void *double_var_helper(void *); | |
extern const size_t double_var_helper_len; | |
__asm__( | |
"double_var_helper:\n" | |
"endbr64\n" | |
"mov %rdi,%rdx\n" | |
"mov double_var_helper_len(%rip), %rdi\n" | |
"mov double_var_helper_len+8(%rip), %rsi\n" | |
"jmp *double_var_helper_len+16(%rip)\n" | |
"double_var_helper_len:\n" | |
".8byte .-double_var_helper" | |
); | |
void *B_inner(void *x, void *y, void *z) { | |
void *yz = ((f)y)(z); | |
return ((f)x)(yz); | |
} | |
void *B_middle(void *x, void *y) { | |
void *state[] = {x, y, B_inner}; | |
return make_function_with_state(double_var_helper, double_var_helper_len, state, sizeof(state)); | |
} | |
void *B(void *x) { | |
void *state[] = {x, B_middle}; | |
return make_function_with_state(single_var_helper, single_var_helper_len, state, sizeof(state)); | |
} | |
void *C_inner(void *x, void *y, void *z) { | |
void *xz = ((f)x)(z); | |
return ((f)xz)(y); | |
} | |
void *C_middle(void *x, void *y) { | |
void *state[] = {x, y, C_inner}; | |
return make_function_with_state(double_var_helper, double_var_helper_len, state, sizeof(state)); | |
} | |
void *C(void *x) { | |
void *state[] = {x, C_middle}; | |
return make_function_with_state(single_var_helper, single_var_helper_len, state, sizeof(state)); | |
} | |
void *K_inner(void *x, void *y) { | |
return x; | |
} | |
void *K(void *x) { | |
void *state[] = {x, K_inner}; | |
return make_function_with_state(single_var_helper, single_var_helper_len, state, sizeof(state)); | |
} | |
void *I(void *x) { | |
return x; | |
} | |
void *S_inner(void *x, void *y, void *z) { | |
void *xz = ((f)x)(z); | |
void *yz = ((f)y)(z); | |
return ((f)xz)(yz); | |
} | |
void *S_middle(void *x, void *y) { | |
void *state[] = {x, y, S_inner}; | |
return make_function_with_state(double_var_helper, double_var_helper_len, state, sizeof(state)); | |
} | |
void *S(void *x) { | |
void *state[] = {x, S_middle}; | |
return make_function_with_state(single_var_helper, single_var_helper_len, state, sizeof(state)); | |
} | |
void *W_inner(void *x, void *y) { | |
f xy = ((f)x)(y); | |
return xy(y); | |
} | |
void *W(void *x) { | |
void *state[] = {x, W_inner}; | |
return make_function_with_state(single_var_helper, single_var_helper_len, state, sizeof(state)); | |
} | |
void *inc(void *x) { | |
return (void *)(1 + (uintptr_t)x); | |
} | |
uintptr_t church_to_int(f church) { | |
f church_inc = church(inc); | |
return (uintptr_t)church_inc(0); | |
} | |
static f zero, succ; | |
f int_to_church(uintptr_t i) { | |
f n = zero; | |
while(i--) { | |
n = succ(n); | |
} | |
return n; | |
} | |
int main(void) { | |
f BS = B(S); | |
f BB = B(B); | |
f plus = BS(BB); | |
f BW = B(W); | |
f BBC = BB(C); | |
f B_BW = B(BW); | |
f S_alt = B_BW(BBC); | |
f BS_alt = B(S_alt); | |
f plus_alt = BS_alt(BB); | |
f mult = B; | |
f exp = C(I); | |
zero = K(I); | |
f one = I; | |
succ = plus(one); | |
f two = succ(one); | |
f three = succ(two); | |
f four = int_to_church(4); | |
f add_three = plus(three); | |
f three_plus_four = add_three(four); | |
f add_three_alt = plus_alt(three); | |
f three_plus_four_alt = add_three_alt(four); | |
f three_of = mult(three); | |
f three_times_four = three_of(four); | |
f three_to = exp(three); | |
f three_fourth = three_to(four); | |
printf("3+4 is %" PRIuPTR "\n", church_to_int(three_plus_four)); | |
printf("3+4 a different way is %" PRIuPTR "\n", church_to_int(three_plus_four_alt)); | |
printf("3*4 is %" PRIuPTR "\n", church_to_int(three_times_four)); | |
printf("3^4 is %" PRIuPTR "\n", church_to_int(three_fourth)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment