GNU-C-Preprocessor, 90 + O(48*n) Bytes
There should be code golf challenges for C preprocessor only, my idea:
#define T(x,...) x
#define D(x,y...) y
#define A(f,x,y) f(x,y)
#define Z5(f,x,y) A(f,T x,T y),Z4(f,(D x),(D y))
#define Z4(f,x,y) A(f,T x,T y),Z3(f,(D x),(D y))
#define Z3(f,x,y) A(f,T x,T y),Z2(f,(D x),(D y))
#define Z2(f,x,y) A(f,T x,T y),Z1(f,(D x),(D y))
#define Z1(f,x,y) A(f,T x,T y)
This example works for input lists of length <= 5. You can call the function like this:
#define C(x,y) x##y
(Z5(C,(h,e,l,l,o),(w,o,r,l,d)))
which results in
(hw,eo,lr,ll,od)
The "n" is the maximum list length to process and output. Of course you could use single characters instead of "Z" as name but using a digit allows for more flexibility and easier maintenance. For example you could add a parameter for "Z" to specify the bounds which is concatenated as Z##n
and used as nested macro call.
The C Preprocessor opens a new realm of languages for code golf and is a rather minimal pure-functional primitive-recursive programming language which only features macro substitutions (which look like function calls, '(', ')', ',' and '#' are the only characters with special meaning), stringification, character concatenation (must be result in valid C tokens) and no direct recursion (each call must be defined with different macro name). Primitive-recursive means, it uses inputs of strictly bounded or fixed lengths and the program always terminates for all inputs. If you want a program for unbounded length, you would need an infinite program but program inputs are always bounded in practice. Literally any strictly limited output for strictly limited input values can be programmed by a primitive-recursive program and thus the C preprocessor. The program only must be big enough to compute it. It can become quite memory-inefficient though.
GNU-C Preprocessor, 238 + O(32*log3(n)) Bytes
A more optimal program size with O(log(n)) program growth is possible but requires hacky additional macro definitions and will only pay off starting with slightly larger input lists. This example purposefully does not add commas between elements in the output to allow for higher flexibility in output.
#define L4(p) L3(p) L3(p) L3(p)
#define L3(p) L2(p) L2(p) L2(p)
#define L2(p) L1(p) L1(p) L1(p)
#define L1(p) p() p() p()
#define T(x,...) x
#define D(x,y...) y
#define I(x...) x
#define W(r,f,a,b,x,y) (I r f(a,b)),f,x,y
#define X(r,f,x,y) W(r,f,T x,T y,(D x),(D y))
#define Y(x...) X(x)
#define C() )
#define O() (
#define U(x...) T(x)
#define Z(f,x,y) U(U(L4(Y O)(),f,x,y L4(C)))
Explanation:
L<x>
is the loop and <x>
is the exponent of how often to loop.
T,U
= take first element from comma-separated list
D
= drop first element from comma-separated list
I
= identity function (evaluates arguments and can remove parens)
A
= applies a function but without lazy argument-evaluation
X,Y,Z
= the actual zipWith function
C
= closing parenthesis, needed for code generation
O
= opening parenthesis, needed for code generation (prevents unclosed macro call errors)
The main idea is to code-generate a long nested expression in a loop so that Z(args)
evaluates to literally Y ( Y ( Y ( ... args' ...) ) )
and Y
reduces the arguments by one step when evaluated in U(U(...))
(it does not work with only one U
).
This example can process up to 3^4 = 243 elements of two lists. If you want to multiply the processing limit by 3, add a new loop line on the top of the code. You need about 20 loop lines to handle unsigned 32-bit of elements. But keep in mind that each element is evaluated, even if does not exist! This is an example which zip-concatenates elements of two lists and places a comma between elements iff the concatenation is not empty:
#define V2(x...) ,##x
#define V(x...) V2(x)
#define CONC(x,y...) y##x
#define CONC1(x,y) V(CONC(y,x))
#define D2(x) (D x)
D2(Z(CONC1,(h,e,l,l,o),(w,o,r,l,d)))
The result is (hw ,eo ,lr ,ll ,od)
. It works with any lists with any number of elements but will output at most 243 elements. Tested on godbolt.org.
If you find improvements which aren't only shorter macro names, please feel free to update this answer and leave a comment.