-
Notifications
You must be signed in to change notification settings - Fork 0
Verbs::Multiply
Multiplication plays a couple of major roles.
Let plural
be defined like:
// Legend:
// ? means past, ?? means future (also analogous to LHS and RHS in a binary operation)
// - past is extracted from... the past - anything that resides in a scope prior to an op
// - future is provided after the op
// one can filter what past/future is required by type constraints:
// number? - we need a number from the past
// number?? - we need a number from the future
// ## means "the idea of ..." - it can be a miles long list of actions, associations and disassociations...
##plural = {(
// Seek numbers from the past, and if n>1, return n (otherwise returns null)
(number? > 1)
or
// Alternatively, just use a range if a number is not found in the past
Range(1, +∞)
// Multiply the number/range by something provided in the future
) * ??}
Here's how that looks with less clutter:
##plural = { ((number? > 1) or Range(1, +∞)) * ?? }
You can use that to define plural forms for any idea:
##houses = ##plural(##house) // the idea of a "house" was provided as future for the idea of "plural"
All the following mean the same thing at different stages of processing:
"Create five houses"
create (5, ##houses) // after being parsed
create (5, ((number? > 1) or Range(1, +∞)) * ##house) // after ##houses was expanded
create ((5 > 1) * ##house) // number was found, so discard the other branch
create (5 * ##house) // the number satisfied the condition (and is returned)
create Thing*5(/*house descriptor*/) // the descriptor absorbed the multiplication
create*5 Thing(/*house descriptor*/) // alternatively, the action can also absorb it
The number might remain undefined, in which case we rely on the context that executes the create
verb to collapse the range. Depending on the context, it might involve user input prompt, randomness, the amount of physical things that fit in a volume, or simply create one element that represents many houses, etc...
"Create houses"
create ##houses
create ((number? > 1) or Range(1, +∞)) * ##house)
create (Range(1, +∞) * ##house) // first branch was discarded - no number in past
This isn't really used in natural languages as far as I'm aware, but can be encoded as well. There are languages that have quite many forms of plurality, some with very weird conditions, so it is useful to take the time and consider a hypothetical partial
form, as an exercise in consistency;
##partial = { ((number? do (>0, <1)) or Range(0, 1)) * ?? }
##applepart = ##partial(##apple)
"create an applepart"
create (1, ##applepart)
create (1, ##partial(##apple))
create (1, (((number? do (>0, <1)) or Range(0, 1)) * ##apple))
create (((1 do (>0, <1)) or Range(0, 1)) * ##apple)) // number found in the past
create (((1>0, 1<1) or Range(0, 1)) * ##apple) // testing the number
create (((1, null) or Range(0, 1)) * ##apple) // test failed
create ((null or Range(0, 1)) * ##apple) // discarding the number branch...
create (Range(0, 1) * ##apple) // not enough information, so rely on the context
Let's try something a bit more convoluted:
##appleparts = ##plural(##applepart)
"create two appleparts"
create (2, ##appleparts)
create (2, ##plural(##partial(##apple)))
create (2, (
((number? > 1) or Range(1, +∞)) * ( // ##appleparts
((number? do (>0, <1)) or Range(0, 1)) * ##apple // ##applepart
)
)
create ((
((2 > 1) or Range(1, +∞)) * (
((2 do (>0, <1)) or Range(0, 1)) * ##apple // inner scopes are executed first
)
)
create ((
((2 > 1) or Range(1, +∞)) * (
Range(0, 1) * ##apple // discarded the inner number
)
)
create (2 * (Range(0, 1) * ##apple)) // discarded the outer range. notice that multiplying these symbols isn't necessarily associative
create*2 (Range(0, 1) * ##apple) // execute `create` two times, each time producing an applepart
// not enough information to collapse the range here, so rely on the context
Or this:
##applehalves = ##plural(0.5, ##applepart)
"create four applehalves"
create (4, ##applehalves)
create (4, ##plural(0.5, ##partial(##apple)))
create (4, (
((number? > 1) or Range(1, +∞)) * ( // ##applehalves
0.5,
((number? do (>0, <1)) or Range(0, 1)) * ##apple // ##applepart
)
)
create ((
((4 > 1) or Range(1, +∞)) * ( // this scope had 4
((0.5 do (>0, <1)) or Range(0, 1)) * ##apple // this scope had 0.5
)
)
create (4 * (0.5 * ##apple)) // all number branches were satisfied. remember - associativity doesn't apply here, because not all objects are numbers (unless ##apple is associated with a number)
create*4 Thing*0.5(/*apple descriptor*/) // but we can still do this. how should we call this rule? the absorbativity rule?
3. Involved in arithmetic and algebra as multiplication/division, often performed at compile-time. This can involve any kind of numbers, matrices, vectors, etc. depending on context.
Simple number multiplication:
// All these mean the same thing
1 * 8
1 multiply 8
1 multiply (8 * 1)
1 multiply*8 1 // absorbativity rule
1 multiply (1 * 8) // commutativity allowed in this case
1 multiply*1 8 // absorbativity rule
Division is the inverse of multiplication, obviously:
// All these mean the same thing
4 / 2
4 multiply*-1 2
4 multiply*-1 (2 * 1)
4 multiply*-2 1 // absorbativity rule with multiplication
4 multiply*-1 (8 / 4)
4 multiply*(-1/8) (1 / 4) // absorbativity rule with division
4 multiply*-0.125 0.25
// Each reversible operation has a negative token; use that instead for readability
// The *-1 is implied in all these cases:
4 divide 2
4 divide (2 * 1)
4 divide*2 1 // absorbativity rule with multiplication
4 divide (8 / 4)
4 divide/8 (1/4) // absorbativity rule with division
4 divide*0.125 0.25
Similar rules apply when multiplying matrices, but commutativity must be taken into account when absorbing:
// column-major 2x2 matrix
Mat2((3, 0), (6, 1)) * Mat2((15, 0), (24, 2))
Mat2(3, 0, 6, 1) multiply Mat2(15, 0, 24, 2)
Mat2(3, 0, 6, 1) multiply*-1 (inverse(Mat2(15, 0, 24, 2))
Mat2(3, 0, 6, 1) divide (inverse(Mat2(15, 0, 24, 2))
Mat2(3, 0, 6, 1) multiply (Mat2(7.5, 0, 12, 1) * Mat2(2, 0, 0, 2)) // can't absorb a matrix; verbs can only receive scalar modifiers
Mat2(3, 0, 6, 1) multiply (Mat2(7.5, 0, 12, 1) * 2) // can't absorb, matrix multiplication is not commutative
Mat2(3, 0, 6, 1) multiply (2 * Mat2(7.5, 0, 12, 1)) // can absorb
Mat2(3, 0, 6, 1) multiply*2 Mat2(7.5, 0, 12, 1) // absorbed
Or vectors:
// Hadamard product of two vectors:
Vec4(1, 2, 3, 4) * Vec4(-1, 0, -1, 0)
// similar shenanigans apply here...
Colors involve multiplication with saturation:
RGBA32(255, 255, 0, 128) * RGBA32(2, 2, 2, 2) // == RGBA32(255, 255, 0, 255)
RGBA32(255, 255, 0, 128) * RGBA32(2) // == RGBA32(255, 255, 0, 255)
RGBA32(255, 255, 0, 128) * 2 // == RGBA32(255, 255, 0, 255)
RGBA32(0xFFFF0080) * 2 // == RGBA32(0xFFFF00FF)
// etc...