hkt-toolbelt
Version:
Functional and composable type utilities
130 lines (129 loc) • 4.67 kB
TypeScript
import { Digit, DigitList, Kind, Type } from '..';
/**
* For each digit in the multiplicand, from right to left, we multiply the digit
* by the multiplier, shift the result to the left by the number of zeroes
* equivalent to the position of the digit, and add the result to the sum of the
* partial products.
*
* Once we have processed all of the digits in the multiplicand, we return the
* sum of the partial products.
*
* This is a type-level implementation of the traditional multiplication
* algorithm, and is O(n^2) in the number of digits.
*/
type _$multiply2<
/**
* The multiplicand.
*/
A extends DigitList.DigitList,
/**
* The multiplier.
*/
B extends DigitList.DigitList,
/**
* As we proceed in the traditional multiplication algorithm, there are a
* number of zeroes that are appended to the end of the partial products.
*
* This type parameter represents the zeroes that are appended to the end of
* the partial products. As we proceed in the algorithm, the number of zeroes
* appended to the end of the partial products increases by one.
*/
SCALE extends DigitList.DigitList = [],
/**
* The sum of the partial products, which we add to as we proceed through each
* digit of the multiplicand.
*/
SUM extends DigitList.DigitList = [],
/**
* The last digit of the multiplicand, which we multiply by the multiplier.
* As we loop through the digits of the multiplicand, we pop the last digit
* off of the multiplicand.
*/
LAST_A extends Digit.Digit = DigitList._$last<A>,
/**
* The next instance of A, with the last digit popped off.
*/
POP_A extends DigitList.DigitList = DigitList._$pop<A>,
/**
* The result of multiplying the last digit of the multiplicand by the
* multiplier.
*/
MUL extends DigitList.DigitList = DigitList._$multiplyDigit<B, LAST_A>,
/**
* Next, we shift the result of the current multiplication by the number of
* zeroes equivalent to the position of the digit, counted from the right.
*/
MUL_SCALE extends DigitList.DigitList = [...MUL, ...SCALE],
/**
* Finally, we add the result of the current multiplication, shifted
* appropriately, to the sum of the partial products.
*/
ADD extends DigitList.DigitList = DigitList._$add<SUM, MUL_SCALE>,
/**
* The next instance of SCALE, with one more zero appended to the end.
*/
NEXT_SCALE extends DigitList.DigitList = [Digit.Zero, ...SCALE],
/**
* If A is empty, we are done, and we return the sum of the partial products.
*/
DONE extends boolean = A extends [] ? true : false> = DONE extends true ? SUM : _$multiply2<POP_A, B, NEXT_SCALE, ADD>;
/**
* `_$multiply` is a type-level function that multiplies a digit list by another digit list.
* It returns the result of the multiplication operation.
*
* @template A - The digit list.
* @template B - A digit list.
*
* @example
* For example, we can use `_$multiply` to multiply a digit list ["4", "2"] by another digit list ["1", "2"]:
*
* ```ts
* import { DigitList } from "hkt-toolbelt";
*
* type Is504 = DigitList._$multiply<["4", "2"], ["1", "2"]>; // ["5", "0", "4"]
* ```
*
* @example
* If one of the inputs is an empty digit list or the zero digit, the result will be the zero digit.
*
* ```ts
* import { DigitList } from "hkt-toolbelt";
*
* type IsZero = DigitList._$multiply<["4", "2"], []>; // ["0"]
* type IsZero2 = DigitList._$multiply<["4", "2"], ["0"]>; // ["0"]
* ```
*/
export type _$multiply<A extends DigitList.DigitList, B extends DigitList.DigitList> = DigitList._$trim<Type._$cast<_$multiply2<A, B>, DigitList.DigitList>>;
interface Multiply_T<T extends DigitList.DigitList> extends Kind.Kind {
f(x: Type._$cast<this[Kind._], DigitList.DigitList>): _$multiply<typeof x, T>;
}
/**
* `Multiply` is a type-level function that multiplies a digit list by another digit list.
* It returns the result of the multiplication operation.
*
* @template A - The digit list.
* @template B - The single digit.
*
* @example
* For example, we can use `Multiply` to multiply a digit list ["4", "2"] by another digit list ["1", "2"]:
*
* ```ts
* import { $, DigitList } from "hkt-toolbelt";
*
* type Is504 = $<$<DigitList.Multiply, ["1", "2"]>, ["4", "2"]>; // ["5", "0", "4"]
* ```
*
* @example
* If one of the inputs is an empty digit list or the zero digit, the result will be the zero digit.
*
* ```ts
* import { DigitList } from "hkt-toolbelt";
*
* type IsZero = $<$<DigitList.Multiply, []>, ["4", "2"]>; // ["0"]
* type IsZero2 = $<$<DigitList.Multiply, ["0"], ["4", "2"]>; // ["0"]
* ```
*/
export interface Multiply extends Kind.Kind {
f(x: Type._$cast<this[Kind._], DigitList.DigitList>): Multiply_T<typeof x>;
}
export {};