Idea: Operator Virtualization Cards
JHawkley opened this issue · 2 comments
Issue type:
- ➕ Feature request
Short description:
Working with Integrated Dynamics, I've noticed that a lot of my effort is spent figuring out how to manipulate the operators into the forms I need them for later transformations. As such, my Variable Stores get filled with operators, flipped versions of operators, partially-applied versions of operators, and the like.
I feel like I spend more time manipulating operators rather than getting useful work done. The mental effort I've expended just trying to create a "Context Binding" operator with a signature of A -> B -> Op[A -> B -> C] -> C
(essentially a rotated apply2
operator) using a series of flips and pipes has seriously broken my mind (and crashed my server a lot too)...
This would all be so much easier if you could just use the Logic Programmer to create operators with the signatures you need from the start.
Proposed Implementation:
A set of four new cards are introduced:
- Virtualization Card - Argument 1
- Virtualization Card - Argument 2
- Virtualization Card - Argument 3
- Virtualization Card - Argument 4
These cards are not variable bindings, but instead are treated as placeholders when inserted into the slots of an operator in the Logic Programmer. They instruct it to create a new operator with the input arguments of some operator mapped to a different position indicated by the Virtualization Card.
They're likely crafted separately from the Logic Programmer and can be re-used; they do not need to be present in a Variable Store for their products to be used.
For brevity, I'll refer to these cards by VCA1, VCA2, VCA3, and VCA4, respectively.
Argument Reordering:
As said, these cards can be used as placeholders in the Logic Programmer and remap the position of an operator's argument. If a Virtualization Card is present in the slots of an operator, the product of binding it to a Variable Card will be a new, virtual operator instead of a card evaluating to the result of the operator's application.
As an example, my "Context Binding" operator could be created by taking the apply2
operator and inserting the cards in the following order:
[VCA3] apply2 [VCA1] [VCA2]
When a Variable Card is bound, it will produce a virtual operator that essentially wraps apply2
, but with re-ordered arguments. It has a psuedo-code implementation of:
var contextBinding: Op[A -> B -> Op[A -> B -> C] -> C]
= a => b => op => (apply2 op a b);
Argument Duplication:
These cards can also be used to map two or more arguments of the source operator to a single argument in the virtual operator.
Taking the numerical add
operator and inserting the cards in the following order:
[VCA1] + [VCA1]
...will yield a virtual operator with the following implementation:
var doubleNumber: Op[Number -> Number]
= n => (add n n);
Partial-Application:
Finally, these cards can also be used to create partially-applied versions of operators; bound Variable Cards can be inserted along-side the Virtualization Cards to create a partially-applied virtual operator.
Let's say I want to create a virtual reduce
operator that already has the target list bound to it; I'll call this list InventoryContents
; it has a variable ID of 1
and a type of List[Item]
.
I can insert cards into reduce
in the following order:
reduce [VCA1] [InventoryContents:1] [VCA2]
This creates a virtual operator with the following implementation:
var reduceInventory: Op[Op[A -> Item -> A] -> A -> A]
= op => initialValue => (reduce op (evalVariableByID 1) initialValue);
Usage Constraints:
The Virtualization Cards have a few constraints associated with their usage in the Logic Programmer:
- The arity of the virtual operator must be maintained. That is, if
VCA2
is inserted, then at least oneVCA1
must also be inserted before the result can be bound to a Variable Card. - When using the argument duplication feature, the types must match. For instance,
slice
has a signature ofList[T] -> Integer -> Integer -> List[T]
; if you were to apply the cards in the orderslice [VCA1] [VCA1] [VCA2]
, then a type mismatch would occur: argumentsList[T]
andInteger
are not compatible and cannot both be mapped to argument 1 of a virtual operator. - If the number and order of arguments of the virtual operator would exactly match the number and order of arguments of the source operator, then binding a Variable Card produces the non-virtualized operator; essentially the same thing you would get inserting a Variable Card into the "Operators" section of the Logic Programmer for that operator. This prevents unnecessary indirection.
Conclusion:
These Virtualization Cards are not meant to replace the higher-order operators apply
and flip
, nor the proposed rotate
operator, but Virtualization Cards will succeed many of the current uses of higher-order operators.
They just make creating and working with operators simpler and more intuitive, while greatly reducing how often a higher-order operator needs to be used to describe a desired process; the number of Variable Cards a complex program will need in its Variable Store would be far reduced.
Good idea! Something like this has been suggested a while ago in #194.
Ahh, I see. I didn't find this issue before I submitted this. Well, hopefully this might be useful as a design for implementing the feature in the future.
This feature, eta-conversions, modular network nodes (IE: combining a reader, writer, and more into one object), and resolving various causes of server/client crashes are my biggest desires for this mod as it continues to develop.
The version shipping with Enigmatica 2 is a bit out-of-date, though; some of those crashes (like the problem with pipe
and multi-argument operators) appear to have been nixed already. I think I'll open an issue to try and get it updated there.