4 ms·
If you have a value "aValue :: a" and a monadic function of "mFunc :: (a -> Maybe b)" that's essentially just asking you to use `>>= :: Maybe a -> (a -> Maybe b
by tobz619 2y ago
If you have a value "aValue :: a" and a monadic function of "mFunc :: (a -> Maybe b)" that's essentially just asking you to use `>>= :: Maybe a -> (a -> Maybe b) -> Maybe b` as well as `pure :: Applicative f => a -> f a` which will lift our regular `aValue` to a `Maybe a` in this instance.
Then to get the result "b" you can use the `maybe :: b -> (a -> b) -> Maybe a -> b` function to get your "b" back and do the weakening as you desire.
`Maybe` assumes a computation can fail, and the `maybe` function forces you to give a default value in the case that your computation fails (aka returns Nothing) or a transformation of the result that's of the same resultant type.
Overall, you'd end up with a function call that looks like:
foo :: b
foo = maybe someDefaultValueOnFailure someFuncOnResult (pure aValue >>= mFunc)
or if you don't want to change the result then you can use `fromMaybe :: a -> Maybe a -> a`
bar :: b
bar = fromMaybe someOtherDefaultValueOnFailure (pure value >>= mFunc) -- if the last computation succeeds, return that value of resultant type of your computation
- cubefox 2y agoPerhaps that theoretically solves the problem, but it sounds awfullly complicated in practice.
- HelloNurse 2y agoThis is fine and understandable in theory, but a usability disaster in practice. If function f returns b or nothing/error, and is then improved to return b always, client code that calls f should not require changes or become invalid, except perhaps for a dead code warning on the parts that deal with the now impossible case of a missing result from f. You are suggesting not only a pile of monad-related ugly complications to deal with the mismatch between b and Maybe b, which are probably the best Haskell can do, but also introducing default values that can only have the practical effect of poisoning error handling.
- the_af 2y ago> If function f returns b or nothing/error, and is then improved to return b always, client code that calls f should not require changes or become invalid Why do you need to change the type signature at all? You "improved" [1] a function to make impossible for the error case to occur, but it's used everywhere and the calling code must handle the error case (I mean, that's what static typing of this sort). So there you have it: the client code is not rendered invalid, it just has dead code for handling a case that will never happen (or more usually, this just bubbles up to the error handler, not even requiring dead code at every call site). As an aside, I don't see the problem with the "pile of monads" and it doesn't seem very complicated. ---- [1] which I assume means "I know I'll be calling this with values that make it impossible for the error to occur". If you are actually changing the code, well, it goes without saying that if the assumptions you made when choosing the type changed when re-writing the function, well... the calling sites breaking everywhere is a strength of static typing.
- HelloNurse 2y agoChanging the type signature (which, by the way, could be at least in easy cases implicitly deduced by the compiler rather than edited by hand) allows new client code to assume that the result is present.
- cubefox 2y ago(or absent in the case of input parameters)
- the_af 2y agoA function in which the input is needed for the computation is very different to one where it's not needed. I would expect the type signature to reflect this, why would you want it otherwise?
- cubefox 2y agoSay you have a function which expects objects of type Foo as an input and which returns objects of type Baz. One day, the function is improved by also accepting the type Bar, i.e. Foo|Bar. So Foo isn't needed for the computation, because Bar is also accepted. Or you have a function which expects objects of type String as an input. But then you realize that in your case, null values can be handled just like empty strings. So the input type can be relaxed to String|Null.
- deleted 2y ago[deleted]
- tobz619 2y agoThere's a difference between empty strings and Null values imo. Just "" != Nothing If you want to handle empty strings as a input in haskell then you have a function of type `f :: String -> b` and you pattern match on your input? f "" = someResult f ... Nothing assumes a proper null in that there is genuinely nothing to work with. Still you can make a function to handle it or use `maybe`?