Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

Functional C

Name: Anonymous 2011-12-12 12:06

is it possible to write C in a functional manner?

Name: Anonymous 2011-12-12 12:09

>>1
google "function pointers"

Name: Anonymous 2011-12-12 12:13

>>2
this. but i don't think it would make your code more clear

Name: Anonymous 2011-12-12 12:32

FP without GC is not fun.

Name: Anonymous 2011-12-12 12:42

>>1
Everything is already passed by value, so you've got that covered.

Name: Anonymous 2011-12-12 14:22

>>3

Yes, but it doesn't matter.

Name: Anonymous 2011-12-12 16:21

>>1
Yes, to an extent, and it's probably a pretty good design pattern.  Use as little state as possible, and comment well when you do.

Name: Anonymous 2011-12-12 16:24

anyone have an example of this

Name: Anonymous 2011-12-12 17:46

Function pointer for lambda, va_arg for partial application, call by value and not global variable for referential transparency and unions as algebraic datatypes.

...or you could just write a LISP interpreter.

Name: Anonymous 2011-12-12 18:16

>>1
it's called python

Name: Anonymous 2011-12-12 18:32

...or you could just CHECK MY DOUBLES.

Name: Anonymous 2011-12-12 18:35

>>10
python is shit gtfo

Name: Anonymous 2011-12-12 22:58


debian:~/host/prog$ cat lambda.c
#include <stdio.h>
#define lambda(return_type, function) \
        ({ \
        return_type __fn__ function __fn__; \
        })

int main()
{
        int (*max)(int,int) = lambda(int, (int x,int y) { return x > y ? x : y; });
        printf("max of 2,6: %d | max of 4,2: %d\n",max(2,6),max(4,2));
        return 0;
}
debian:~/host/prog$ gcc lambda.c
debian:~/host/prog$ ./a.out
max of 2,6: 6 | max of 4,2: 4

Name: Anonymous 2011-12-12 23:11

>>12
Lisp is worse lol

Name: Anonymous 2011-12-13 6:37


#include <stdio.h>


int t1(char* string, FILE* out) {
  return (*string == '\0') ? 0
                           : (((out == stdout) ? t1(string + 1, stderr)
                                              : t1(string + 1, stdout)),
                              fputc(*string, out));
}

int main(int argc, char** argv) {
  return (argc == 0) ? 0
                     : ((t1(*argv, stdout), fputc('\n', stdout)),
                        main(argc - 1, argv + 1));
}

Name: F r o z e n V o i d !!mJCwdV5J0Xy2A21 2011-12-13 6:39

>>15
Looks like someone trying to write Lisp in C.

Name: Anonymous 2011-12-13 6:44

>>16

It actually works though. The ?: syntax lets you create conditions that evaluate as expressions, and the (expression1, expression2, ..., expression_n) syntax is equivalent to lisp's: (begin expression1 expression2 ... expression_n), where each expression is evaluated one after the other and the value of the last expression_n is returned.

Name: F r o z e n V o i d !!mJCwdV5J0Xy2A21 2011-12-13 6:47

>>17
Its called ternary. Also try the && syntax(Logical AND) which "lazily evaluates" the arguments, just like Haskell.

Name: Anonymous 2011-12-13 6:49

>>13
Cool GNU extensions, bro.

Name: Anonymous 2011-12-13 6:58

Name: Anonymous 2011-12-13 7:47

>>18

oh yeah, I forgot about that. You can implement something similar to exceptions by connecting all your statements with && and returning true after normal execution, and false from an exception. Unfortunately, (a||b) seems to return either 0 or 1. It would be nice if it returned a if a was true, or b when a was false. If that was the case, then exceptions could be implemented with pointers like this:



#include <malloc.h>
#include <stdio.h>
#include <assert.h>


typedef struct exception_vtable* exception_header;
typedef exception_header* exception;

struct exception_vtable {
  void (*print)(FILE* output, exception self);
};


struct invalid_int_argument_exception {
  exception_header header;
  int argument;
};

void print_invalid_int_argument_exception(FILE* output, exception self) {
  fprintf(output, "invalid_argument_exception: arg: %d\n", ((struct invalid_int_argument_exception*)*self)->argument);
}

struct exception_vtable invalid_int_argument_exception_vtable = {
  print_invalid_int_argument_exception
};

exception invalid_int_argument_exception(int argument) {
  struct invalid_int_argument_exception* x = malloc(sizeof(struct invalid_int_argument_exception));
  assert(x);
  x->header = &invalid_int_argument_exception_vtable;
  x->argument = argument;
  return (exception)x;
}

#define NO_EXCEPTION ((void*)0)



exception factorial_loop(int n, int accumulation, int* ret) {
  return (n == 0) ? (*ret = accumulation, NO_EXCEPTION)
                  : factorial_loop(n - 1, accumulation * n, ret);
}

exception factorial(int n, int* ret) {
  return (n < 0) ? invalid_int_argument_exception(n)
                 : factorial_loop(n, 1, ret);
}

exception print_factorial_of_string(char* string) {
  int n_fact; // This explicit stack allocation might not be all that functional. It is always better to allocate shit on the heap.
  return factorial(atoi(string), &n_fact) ||
         (printf("%s! is %d\n", string, n_fact),
          NO_EXCEPTION);
}

exception print_factorial_of_args(int arg_count, char** arg_array);
exception print_factorial_of_args(int arg_count, char** arg_array) {
  return (arg_count == 0) ? NO_EXCEPTION
                          : (print_factorial_of_string(*arg_array) ||
                             print_factorial_of_args(arg_count - 1, arg_array + 1));
}

int exit_with_exception(exception e) {
  return (e == NO_EXCEPTION) ? 0
                             : (fprintf(stderr, "Uncaught Exception: "),
                                (*e)->print(stderr, e),
                                fprintf(stderr, "\n"),
                                free(e),
                                1);
}

int main(int argc, char** argv) {
  return exit_with_exception(print_factorial_of_args(argc - 1, argv + 1));
}



But it doesn't work. For shame.

Name: F r o z e n V o i d !!mJCwdV5J0Xy2A21 2011-12-13 8:39

>It would be nice if it returned a if a was true, or b when a was false.
a?a:b will do this
(a||b) will return 1 if a==true OR (Not A and b)==true, the case when both A and B are true ,A triggers first.

Don't change these.
Name: Email:
Entire Thread Thread List