Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * =============================================================================================================
- * Monads!
- * -------
- * Adapted from: https://youtu.be/C2w45qRc3aU?t=295
- * =============================================================================================================
- */
- /**
- * A Loggable type that wraps a value of type T and logs associated with transformations.
- */
- type Loggable<T> = { value: T, logs: string[] }
- /**
- * Wraps a given value in a Loggable object with an empty logs array.
- *
- * @param value - The value to be wrapped.
- * @returns A Loggable object containing the value and an empty logs array.
- */
- const toLoggable = <T>(val: T): Loggable<T> => ({ value: val, logs: [] })
- /**
- * Applies a transformation to a Loggable value of type X, concatenating the logs of the original
- * and transformed values, and returns a new Loggable object of type Y.
- *
- * @param loggable - The initial Loggable value.
- * @param transform - A function that transforms the value of type X and returns a new Loggable object of type Y.
- * @returns A new Loggable object with the transformed value and concatenated logs.
- */
- const apply = <X, Y>(loggable: Loggable<X>, transform: (v: X) => Loggable<Y>): Loggable<Y> =>
- ((result) => ({
- value: result.value,
- logs: [...loggable.logs, ...result.logs]
- }))
- (transform(loggable.value))
- /**
- * Squares a number and logs the transformation.
- *
- * @param n - The number to be squared.
- * @returns A Loggable object containing the squared value and the log of the transformation.
- */
- const square = (n: number): Loggable<number> => ({ value: n * n, logs: [`Squared ${n} to get ${n * n}`] })
- /**
- * Adds one to a number and logs the transformation.
- *
- * @param n - The number to which one is added.
- * @returns A Loggable object containing the incremented value and the log of the transformation.
- */
- const addOne = (n: number): Loggable<number> => ({ value: n + 1, logs: [`Added 1 to ${n} to get ${n + 1}`] })
- // Perform immutable transformations
- const a = apply(toLoggable(3), square) // Squared 3 to get 9
- const b = apply(a, addOne) // Added 1 to 9 to get 10
- const c = apply(b, square) // Squared 10 to get 100
- console.log(`Result: ${c.value}`)
- console.log(JSON.stringify(c.logs, null, 2))
- /*
- * =============================================================================================================
- * Rust-like options
- * =============================================================================================================
- */
- /**
- * An Option type that can contain a value of type T or be None.
- */
- type Option<T> = Some<T> | None
- /**
- * A Some type that wraps a value of type T.
- */
- class Some<T> {
- readonly kind = 'some'
- constructor(public readonly value: T) {}
- }
- /**
- * A None type that represents the absence of a value.
- */
- class None {
- readonly kind = 'none'
- }
- /**
- * Helper function to create a Some instance.
- *
- * @param value - The value to wrap in a Some.
- * @returns An Option containing the value.
- */
- const some = <T>(val: T): Option<T> => new Some(val)
- /**
- * Helper function to create a None instance.
- *
- * @returns An Option representing the absence of a value.
- */
- const none = (): Option<never> => new None()
- /**
- * Roman numeral symbols and their corresponding values.
- */
- const romanSymbols: [string, number][] = [
- ['M', 1000], ['CM', 900], ['D', 500], ['CD', 400],
- ['C', 100], ['XC', 90], ['L', 50], ['XL', 40],
- ['X', 10], ['IX', 9], ['V', 5], ['IV', 4],
- ['I', 1]
- ]
- /**
- * Converts an integer to a Roman numeral string recursively.
- *
- * @param num - The integer to convert.
- * @param index - The current index in the romanSymbols array (default is 0).
- * @returns A string representing the Roman numeral.
- */
- const intToRomanInner = (num: number, index: number = 0): string => {
- if (num === 0) return ''
- const [romanSymbol, value] = romanSymbols[index]
- return num >= value
- ? romanSymbol + intToRomanInner(num - value, index)
- : intToRomanInner(num, index + 1)
- }
- /**
- * Converts an integer to a Roman numeral wrapped in an Option type.
- *
- * @param num - The integer to convert.
- * @returns An Option containing the Roman numeral string or None if input is invalid.
- */
- const intToRoman = (num: number): Option<string> => {
- if (isNaN(num) || num < 1) return none()
- return some(intToRomanInner(num))
- }
- /**
- * Converts an integer to a Roman numeral wrapped in a Loggable object.
- *
- * @param n - The integer to convert.
- * @returns A Loggable object containing the Roman numeral and a log of the transformation.
- */
- const toRoman = (n: number): Loggable<string> =>
- (result => ({ value: result, logs: [`Converted ${n} to Roman numeral ${result}`] }))
- (handleOption(intToRoman(n), ''))
- /**
- * Function to handle Option values.
- *
- * @param opt - The Option value to handle.
- * @param defaultValue - The default value to return if the Option is None.
- * @returns The value contained in Some or the default value if None.
- */
- const handleOption = <T>(opt: Option<T>, defaultValue: T): T => {
- switch (opt.kind) {
- case 'some': return opt.value
- case 'none': return defaultValue
- }
- }
- // Example usage
- const example1 = intToRoman(3549) // Some("MMMDXLIX")
- const example2 = intToRoman(0) // None
- const example3 = intToRoman(NaN) // None
- // console.log(example1) // Some { kind: 'some', value: 'MMMDXLIX' }
- // console.log(example2) // None { kind: 'none' }
- // console.log(example3) // None { kind: 'none' }
- // console.log(handleOption(example1, '')) // "MMMDXLIX"
- // console.log(handleOption(example2, '')) // ""
- // console.log(handleOption(example3, '')) // ""
- const x = apply(toLoggable(9), square) // Squared 9 to get 81
- const y = apply(x, toRoman) // Converted 81 to Roman numeral LXXXI
- console.log(`Result: ${y.value}`)
- console.log(JSON.stringify(y.logs, null, 2))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement