User:PkmnQ/Alternate Universe Underload
- This is still a work in progress. It may be changed in the future.
This is an exploration of what would change if Underload had its ~
command was replaced with a different command, which will be represented with _
.
Command
- _ : (x) (y) — y (x)
- Similar to ^, the top element is popped from the stack and run as part of the program, however the new topmost element is ignored until the command ends.
(For those familiar with Forth, Factor, etc., if ~
is swap
, _
is dip
.)
Translating between Underload and Alternate Universe Underload
~
in Alternate Universe Underload is simply a_
Expressing _
in Underload can be done with ~a*^
.
Examples
Fibonacci sequence
(()(*))((:^:S*a(^a(!)_)_*)_(/)S:^):^
Unlambda to Alternate Universe Underload
Alternate Universe Underload minimization
^
is no longer necessary, since_
also allows for control flow. In fact, either^
or_
can be implemented using the other:
^ = ()a__! or (())__! _ = a(!(a(!)))a*:*^!a*^a(*)**a:*^!a*^ or a((!(a(!))))*:*^!a*^a(*)**a:*^!a*^
- Removing
!
is mostly the same as in regular Underload:
{(x)} = ({x})a_ or (({x}))_ {xy...z} = {x}{y}...{z} {x} = (x)_ for all x made up of _:*S {!} = * or if you want nicely formatted junk, a_a* or (a)_* {a} = (aa(_)*)_ or (a(a_)*)_ {^} = a_^ Call the whole program as (){P}.
^
can also be easily removed from the above:
{^} = a_(()a___) or a_((())___)
Something that only uses :!()_
Removal of !
from :!()_
programs
Giving the running program an argument is no longer a problem unlike for :()^
, since _
serves that purpose.
The transformation used will have these properties:
(()){P}
behaves equivalently to the null program, i.e.{P}
deletes the(())
from the stack with no other effect.({A1})...({An})((())_){P}
behaves equivalently to(A1)...(An)P
.
One useful construction is this:
<P|Q> = (()(P)(_Q)(_)())_____(())___ (())<P|Q> = (())(()(P)(_Q)(_)())_____(())___ = ()(P)(_Q)(_)()(())____(())___ = ()(P)(_Q)(_)()()___(())___ = ()(P)(_Q)(_)_(())___ = ()(P)_(_Q)(())___ = P()(_Q)(())___ = P()()(_Q)__ = P()_Q()_ = PQ ((())_)<P|Q> = ((())_)(()(P)(_Q)(_)())_____(())___ = ()(P)(_Q)(_)()((())_)____(())___ = ()(P)(_Q)(_)(())_()___(())___ = ()(P)(_Q)()(_)()___(())___ = ()(P)(_Q)()(_)__(())___ = ()(P)(_Q)_()_(())___ = ()_Q(P)(())___ = Q()(P)__ = QP()_ = QP
The transformation also assumes the program always has at least one element on the stack (there is no way to delete a singular stack element using only _
), which can be accomplished by prepending ()
to a program that never underflows the stack.
The transformation rules are:
{} = (()())_____ {PQ} = :({P})_{Q} {:} = {!} = {(P)} = (({P}))_{:}((())())___ {_} =
"Lambda" terms and abstraction elimination
The only change to the conversion rules is that this rule:
[(x)-(A)(x)] = :[(x)-(A)]~
Changes to this:
[(x)-A(x)] = :[(x)-(A)]_
There may be more optimizations that can be made specifically for Alternate Universe Underload (e.g. currently [(x)-Ax]
becomes :[(x)-((A))]_*^
when :[(x)-(A)]_^
is shorter), but the above is the smallest change that is needed to make the conversion work.