• arc@lemm.ee
    link
    fedilink
    arrow-up
    0
    arrow-down
    1
    ·
    2 years ago

    Swift and Rust have a far more elegant solution. Swift has a pseudo throw / try-catch, while Rust has a Result<> and if you want to throw it up the chain you can use a ? notation instead of cluttering the code with error checking.

      • m_f
        link
        fedilink
        arrow-up
        0
        ·
        2 years ago

        It’s not a half-arsed copy, it’s borrowing a limited subset of HKT for a language with very different goals. Haskell can afford a lot of luxuries that Rust can’t.

      • arc@lemm.ee
        link
        fedilink
        arrow-up
        0
        ·
        2 years ago

        You can say it’s half-arsed if you like, but it’s still vastly more convenient to write than if err != nil all over the place

      • Nevoic@lemmy.world
        link
        fedilink
        English
        arrow-up
        0
        ·
        edit-2
        2 years ago

        Note: Lemmy code blocks don’t play nice with some symbols, specifically < and & in the following code examples

        This isn’t a language level issue really though, Haskell can be equally ergonomic.

        The weird thing about ?. is that it’s actually overloaded, it can mean:

        • call a function on A? that returns B?
        • call a function on A? that returns B

        you’d end up with B? in either case

        Say you have these functions

        toInt :: String -> Maybe Int
        
        double :: Int -> Int
        
        isValid :: Int -> Maybe Int
        

        and you want to construct the following using these 3 functions

        fn :: Maybe String -> Maybe Int
        

        in a Rust-type syntax, you’d call

        str?.toInt()?.double()?.isValid()
        

        in Haskell you’d have two different operators here

        str >>= toInt &lt;&amp;> double >>= isValid
        

        however you can define this type class

        class Chainable f a b fb where
            (?.) :: f a -> (a -> fb) -> f b
        
        instance Functor f => Chainable f a b b where
            (?.) = (&lt;&amp;>)
        
        instance Monad m => Chainable m a b (m b) where
            (?.) = (>>=)
        

        and then get roughly the same syntax as rust without introducing a new language feature

        str ?. toInt ?. double ?. isValid
        

        though this is more general than just Maybes (it works with any functor/monad), and maybe you wouldn’t want it to be. In that case you’d do this

        class Chainable a b fb where
            (?.) :: Maybe a -> (a -> fb) -> Maybe b
        
        instance Chainable a b b where
            (?.) = (&lt;&amp;>)
        
        instance Chainable a b (Maybe b) where
            (?.) = (>>=)
        

        restricting it to only maybes could also theoretically help type inference.