oscbyspro / Ultimathnum

Binary arithmetic reimagined in Swift
Apache License 2.0
9 stars 1 forks source link

Add: Fallible/sink(_:) #116

Closed oscbyspro closed 4 weeks ago

oscbyspro commented 1 month ago

I'm working on more maintainable redemption arcs. Of note, this operation scales well:

var value = U8(3)
var error = false

value = value.decremented().sink(&error) // value:   2, error: false
value = value.decremented().sink(&error) // value:   1, error: false
value = value.decremented().sink(&error) // value:   0, error: false
value = value.decremented().sink(&error) // value: 255, error: true

extension Fallible {

    // Returns the `value` by setting the `remote` indicator on `error`.
    @inlinable public consuming func sink(_ remote: inout Bool) -> Value { ... }
}

Depending on how the new approach turns out, I may revisit mutating methods. We'll see.

Notes on Fallible/map(_:)

Fallible/map(_:) works in simple cases but it quickly devolves into a pyramid-of-doom.

oscbyspro commented 1 month ago

Note that this method makes it straightforward to use a single error indicator for an entire algorithm in cases where the implicit error propagation approach uses one error indicator per named entity. In the exponentiation algorithm, for example, the power and multiplier both manage an error indicator. With this approach, you can just sink all multiplication errors.

oscbyspro commented 1 month ago

Generating the Bool is one of the pain-points. So I'll add some static sink(_:) too:

extension Fallible {

    /// Generates an `error` indicator then combines it at the end of the `action`.
    @inlinable public static func sink(_ action: (inout Bool) -> Value) -> Self { ... }

    /// Generates an `error` indicator then combines it at the end of the `action`.
    @inlinable public static func sink(_ action: (inout Bool) -> Self ) -> Self { ... }
}

Here's just some examples uses cases from one of my randomized multiplication tests:

let foo = Fallible<T>.sink {
    lhs.plus(rhs).sink(&$0).squared()
}

let bar = Fallible<T>.sink {
    let a: T = lhs.squared( ).sink(&$0)
    let b: T = lhs.times(rhs).sink(&$0).times(2).sink(&$0)
    let c: T = rhs.squared( ).sink(&$0)
    return a.plus(b).sink(&$0).plus(c )
}
oscbyspro commented 1 month ago

I'm not sure how easy it is to appreciate the simplicity of it vs (#117), but it's great.