hkt-toolbelt
Version:
Functional and composable type utilities
120 lines (119 loc) • 5.28 kB
TypeScript
import { Type, Kind, Digit, DigitList } from '..';
type _$divideBySubtraction2<
/**
* A represents the digit list to be divided, i.e., the dividend.
*/
A extends DigitList.DigitList,
/**
* B represents the digit list by which A is to be divided, i.e., the
* divisor.
*/
B extends DigitList.DigitList,
/**
* OPERATION specifies the operation to perform (either "DIVIDE" or "MODULO").
*
* Default is "DIVIDE". The reason that we 'combine' the divide and modulo
* operations into one implementation is that they're very similar in nature,
* and the only difference is the final result.
*/
OPERATION extends 'DIVIDE' | 'MODULO' = 'DIVIDE',
/**
* QUOTIENT is our current guess and accumulator of the result of division.
* Initially, it is assigned '0' - so that we can increment it as we subtract
* from the remainder.
*/
QUOTIENT extends DigitList.DigitList = [Digit.Zero],
/**
* REMAINDER or the rest of the numbers that were not yet covered by the
* multiples of B, starts as the original input number A.
*
* As we iterate, we reduce this variable by subtracting B from it. Once
* REMAINDER is less than B, we know that we've covered all the multiples of B
* in A, and that the remainder is the result of the modulo operation.
*/
REMAINDER extends DigitList.DigitList = A,
/**
* NEXT_QUOTIENT prepares our next version of the quotient by incrementing
* the current one, to be carried over to the next operation.
*/
NEXT_QUOTIENT extends DigitList.DigitList = DigitList._$increment<QUOTIENT>,
/**
* NEXT_REMAINDER is the result of subtracting the divisor B from the current
* remainder, which will be carried into the next round of operation.
*/
NEXT_REMAINDER extends DigitList.DigitList = DigitList._$subtract<REMAINDER, B>,
/**
* PERFECTLY_DIVISIBLE indicates if the remainder is perfectly divisible by B.
*/
PERFECTLY_DIVISIBLE extends boolean = REMAINDER extends B ? true : false,
/**
* DONE is a type predicate that helps us establish if we've successfully
* completed the division operation - when the remainder equals 0 or when the
* number is perfectly divisible by the divisor.
*/
DONE extends boolean = NEXT_REMAINDER extends [Digit.Zero] ? true : PERFECTLY_DIVISIBLE,
/**
* DIV_RESULT holds the final result of division if A was perfectly divisible
* by B.
*/
DIV_RESULT extends DigitList.DigitList = PERFECTLY_DIVISIBLE extends true ? NEXT_QUOTIENT : QUOTIENT,
/**
* MOD_RESULT holds the final result of modulo operation if A was perfectly
* divisible by B.
*/
MOD_RESULT extends DigitList.DigitList = PERFECTLY_DIVISIBLE extends true ? [Digit.Zero] : REMAINDER,
/**
* RESULT holds the final result of the operation.
*/
RESULT extends DigitList.DigitList = OPERATION extends 'DIVIDE' ? DIV_RESULT : MOD_RESULT> = DONE extends true ? RESULT : _$divideBySubtraction2<A, B, OPERATION, NEXT_QUOTIENT, NEXT_REMAINDER>;
/**
* `_$divideBySubtraction` is a type-level function that performs the division or modulo operation by subtraction.
* It takes in two digit lists `A` and `B` representing the dividend and divisor respectively, and an operation type
* which can be either "DIVIDE" or "MODULO". It returns the result of the operation (division or substraction).
*
* @template A - A digit list representing a number to divide.
* @template B - A digit list representing a number to divide by.
* @template OPERATION - A string type representing the operation to be performed. Can be either "DIVIDE" or "MODULO".
*
* @example
* For example, we can use `_$divideBySubtraction` to divide a digit list representing the number 10 by 2:
*
* ```ts
* import { DigitList } from "hkt-toolbelt";
*
* type Result = DigitList._$divideBySubtraction<["1", "0"], ["2"]>; // ["5"]
* ```
*
* @example
* We can also use `_$divideBySubtraction` to find the remainder when a digit list representing the number 123 is divided by 17:
*
* ```ts
* import { DigitList } from "hkt-toolbelt";
*
* type Result = DigitList._$divideBySubtraction<["1", "2", "3"], ["1", "7"], "MODULO">; // ["4"]
* ```
*/
export type _$divideBySubtraction<A extends DigitList.DigitList, B extends DigitList.DigitList, OPERATION extends 'DIVIDE' | 'MODULO' = 'DIVIDE'> = B extends [Digit.Zero] ? [Digit.Zero] : B extends ['1'] ? OPERATION extends 'DIVIDE' ? A : [Digit.Zero] : _$divideBySubtraction2<A, B, OPERATION>;
interface DivideBySubtraction_T<A extends DigitList.DigitList> extends Kind.Kind {
f(x: Type._$cast<this[Kind._], DigitList.DigitList>): _$divideBySubtraction<A, typeof x>;
}
/**
* `DivideBySubtraction` is a type-level function that performs a division by subtraction.
* It returns the result of the division.
*
* @template A - A digit list representing a number to divide.
* @template B - A digit list representing a number to divide by.
*
* @example
* For example, we can use `DivideBySubtraction` to divide a digit list representing the number 10 by 2:
*
* ```ts
* import { $, DigitList } from "hkt-toolbelt";
*
* type Result = $<$<DigitList.DivideBySubtraction, ["1", "0"]>, ["2"]>; // ["5"] quotient is 5, and the remainder is 0.
* ```
*/
export interface DivideBySubtraction extends Kind.Kind {
f(x: Type._$cast<this[Kind._], DigitList.DigitList>): DivideBySubtraction_T<typeof x>;
}
export {};