This is not the most serious answer, but you could use the following. Its most practical use is if you want a simple counter or something like that. It works with binary representations of numbers, where True means 1 and False means 0. It is based on the concept of a half adder. Don't be fooled by the quasi informative comments that may give the impression that the code is understandable, in the end the code has become quite write-only.
nn = 2;
(*first argument (input) is the carry*)
(*output[[1]] is the value *)
(*output[[2,1]] is the carry *)
(*output[[2,2;;]] is the rest of the numbers that have to be added *)
retainingHalfAdd =
Function @@
Function[Null, Hold@{Xor[#, #2], {# && #2, ##3, False}}, HoldAll] @@
Part @@@ Hold @@ ({Slot @@ {1}, #} & /@ Range[nn + 1]);
cyclerReducer =
List @@@
Function@Evaluate@
Join[
Hold[#[[1, 2]]],
Apply[Part,
Hold@Evaluate@
Append[{Slot @@ {1}, 2, #} & /@ Range[2, nn + 1], {#, 1, 1}]
, {2}]
];
halfAddStep = cyclerReducer@{retainingHalfAdd[#[[1]]], #[[2]]} &;
argListHeld =
List @@@ Hold@Evaluate@
Append[
List @@@ Hold@Evaluate@
Prepend[
Part @@@
Hold @@
({Slot @@ {1}, # } & /@ Range[nn]),
True],
ConstantArray[False, nn + 1]
];
plusOne =
Part @@@ Function@Evaluate@
Append[Nest[Unevaluated@halfAddStep /@ # &, argListHeld, nn + 1],
2];
plusOneCode =
plusOne //.
Join[
Join @@
OwnValues /@
Unevaluated@{argListHeld, halfAddStep, cyclerReducer, listRHA,
retainingHalfAdd, nn}
,
{And -> FEPrivate`And, Xor[x_, y_] :> SameQ[SameQ[x, y], False]}
];
Here are some tests to see how plusOne can be used
testFu =
FromDigits[Reverse@#, 2] &@
Boole@Most@
Nest[plusOne, OddQ /@ Reverse@IntegerDigits[#, 2, nn], #2] &;
plusOne[ConstantArray[False, nn]]
Nest[plusOne, ConstantArray[False, nn], 2^nn]
{True,False,False}
{False,False,True}
We can use the function like plus, but we will have to add 1 a lot of times.
testFu[#, #2] == Mod[# + #2, 2^nn] &[324232, 3445]
True
Using the following, we see that it can work completely in the Front End. We use plusOneCode instead of plusOne, because a few modifications were needed to make it work Front-End-only. Click the square a few times to toggle the colour. Uncomment the comment to see that we are counting using x.
ReleaseHold[
ReplaceAll[#,
Join[OwnValues[
plusOneCode], {startCount -> ConstantArray[False, nn + 1],
targetCount -> Append[ConstantArray[False, nn], True]}]] &@
Hold@
DynamicModule[{x, y = False},
x = startCount;
Column@
{
Graphics@
{
DynamicBox[If[y, RGBColor[1, 0, 1], RGBColor[0, 1, 0]]],
EventHandler[
Rectangle[{0, 0}], "MouseDown" :> (
FEPrivate`Set[y,
SameQ[FEPrivate`Set[x, plusOneCode[x]], targetCount]]
)
]
}
(*,
Dynamic[Column@x]*)
}
]
]
The following shows that doings things in the kernel is about 20x faster
feTimingFunc = (Function @@ Nest[plusOneCode /@ # &, Hold[#], 500]);
kerTimingFunc = (Function @@ Nest[plusOne /@ # &, Hold[#], 500]);
kerRes = kerTimingFunc[ConstantArray[False, nn + 1]]; //
AbsoluteTiming // First
ReleaseHold[
Hold[
feRes = FE`Evaluate@feTimingFunc[input]
] /.
Append[OwnValues[feTimingFunc],
input -> ConstantArray[False, nn + 1]]
] // AbsoluteTiming // First
0.013697
0.210329
Somehow something breaks down if we nest the function more than 500 times, probably the front ends recursion limit is reached. Timings are quite acceptable compared to other delays when using Dynamic, in my opinion.
1+1so that FE adds it by itself instead of sending to the main Kernel. And I don't care how it will be done :) – Kuba Oct 04 '16 at 18:40