UNPKG

hkt-toolbelt

Version:

Functional and composable type utilities

130 lines (129 loc) 4.67 kB
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 {};