Shortening t.s
Favor recursion over while loop
Given your t.s
function
t.s=_=>{o="";while(i=t.o()){o+=i+","}return o}
Observe that o
is a simple accumulator, so we can easily convert the loop into a recursive function. There are several ways to write the recursive function:
// explicit accumulator, aka tail-recursion
t.s=(o="")=>(i=t.o())?t.s(o+i+","):o
// implicit accumulator, shorter, saves 15 bytes from OP's code
t.s=_=>(i=t.o())?i+","+t.s():""
i+","+t.s()
can be shortened to i+[,t.s()]
, saving 1 byte.
Shortening the rest
Initialize the second parameter of t.e
to h
The function t.e
is using (l||h)
several times, just to handle the initial call. JS's default argument is very permissive, so we can do this:
// instead of
t.e=(i,l)=>h=(l||h)==E?[i,E]:[(l||h)[0],t.e(i,(l||h)[1])];
// do this
t.e=(i,l=h)=>h=l==E?[i,E]:[l[0],t.e(i,l[1])];
Simplify base case
Instead of E=[N,N]
, simply E=[]
works too. This has several golfing opportunities regarding string coercion:
h==E
is equivalent to h==[]
, and []
coerces to ""
. Anything that stringifies into something other than ""
is greater than E
, so we can rewrite h==E?A:B
into h>E?B:A
.
h
is now a linked list where 3::2::1::nil
looks like [3,[2,[1,[]]]]
, which exactly stringifies into "3,2,1,"
. So we can simply coerce h
to string: t.s=_=>h+""
, or even better, t.s=_=>h+E
.
Array unpacking
We can slightly do better here too:
// instead of
t.o=_=>h>E?h[+!(h=h[1])]:N;
// do this
t.o=_=>h>E?([a,h]=h,a):N;
And this also applies to t.e
:
// instead of this
t.e=(i,l=h)=>h=l>E?[l[0],t.e(i,l[1])]:[i,E];
// do this
t.e=(i,[a,l]=h)=>h=l?[a,t.e(i,l)]:[i,E];
I chose l?
because whenever h
is nonempty, l
is a reference so it always evaluates to true. If h
is empty, both a
and l
become undefined
.
Side note: I found that the OP's code actually works with falsy list items, because the only real comparison is h==E
, that is, comparing stringification reference of whole array. Whatever E
is, h==E
cannot be true if the list h
has at least one item, since its string will have at least one more comma than E
's the reference becomes different.
Final result, 125 121 bytes
function L(){h=E=[];t=this;t.u=i=>h=[i,h];t.o=_=>h>E?([a,h]=h,a):null;t.e=(i,[a,l]=h)=>h=l?[a,t.e(i,l)]:[i,E];t.s=_=>h+E}
Try it online!
As a side note, I think
t.o()
fails if the list contains a0
(or any other falsy value that may actually appear in the list), because it's treated the same way as anull
. I assume that you're only asking for a golfed version, bugs included. :) But you may want to clarify this point. – Arnauld – 2019-12-10T00:23:21.670@Arnauld I mentioned that as a disclaimer on my answer. I'm new, and not sure if that's a violation of the rules. Also wasn't sure if I should copy-paste all that into this question. – Daniel Franklin – 2019-12-10T00:24:39.070
Oh I see. I overlooked the footnote in your answer. – Arnauld – 2019-12-10T00:26:09.303
@Arnauld If someone figured out a better way to do t.o that didn't have that issue (without just replacing
+!
. with an equality test that adds a few bytes) I'd definitely consider that a valid answer to this question. – Daniel Franklin – 2019-12-10T00:27:40.127