4 ms·
I don't use Haskell, so this is a dumb question. Why can't X be implicitly cast to Maybe X?
by magicalhippo 2y ago
I don't use Haskell, so this is a dumb question. Why can't X be implicitly cast to Maybe X?
- tobz619 2y agoIt can using pure or return or if working with just Maybe specifically then Maybe is defined like so: data Maybe a = Just a | Nothing So to make an X a Maybe X, you'd put a Just before a value of type X. For example: one :: Int one = 1 mOne :: Maybe Int mOne = Just one -- alternatively, pure one since our type signature tells us what pure should resolve to. Reason we can do this is because Maybe is also an Applicative and a Monad and so implements pure and return which takes an ordinary value and wraps it up into an instance of what we want.
- cubefox 2y agoIsn't that explicit casting? Implicit casting would be automatically performed by the compiler without the need to (re)write any explicit code.
- ninkendo 2y agoSounds similar to how you need to do Some(x) when passing x to something expecting an Option in rust. Swift interestingly doesn’t require this, but only because Optionals are granted lots of extra syntax sugar in the language. It’s really wrapping it in .some(x) for you behind the scenes, but the compiler can figure this out on its own. This means that in swift, changing a function from f(T) to f(T?) (ie. f(Optional<T>)) is a source-compatible change, albeit not an ABI-compatible one.
- magicalhippo 2y ago> mOne = Just one I'd call that explicit casting. Implicit casting would be mOne = one Compiler already knows what "one" is, it could insert the "Just" itself, no? Possibly due to an operator defined on Maybe that does this transformation? That is, are there some technical reasons it doesn't? Or is it just (no pun inteded) a language choice?
- yakshaving_jgt 2y agoWhy would this be useful? Why do you want the types to change underneath you?
- cubefox 2y agoBetter question: Why would you want your call site code to break when your type signature gets changed in a way that doesn't necessitate breaking anything?
- yakshaving_jgt 2y agoBecause what you're asking for precludes the concept of mathematical guarantees. I'm not taking your question at face value, because you could be asking why call site code should break when the type signature generalises (which is a useful thing), but that's not what you're asking. It seems you're asking for code to be both null safe and not null safe simultaneously. Having a language just decide that it would like to change the types of the values flowing through a system is wild. It's one of the reasons that JavaScript is a trash fire.
- cubefox 2y agoYou are misunderstanding things.
- yakshaving_jgt 2y agoI’m certainly misunderstanding why so many people in this thread insist on speaking authoritatively on a topic they clearly know very little about.
- magicalhippo 2y agoBecause it otherwise forces the caller to have an extra explicit step that doesn't really contribute to anything. It's a trivial transform, and as such just gets in the way of what the code actually does. Of course with great power comes great responsibility, so it's a tool that should be used sparingly and deliberately. Now as mentioned I don't use Haskell, but that's why I like it in other languages. I asked as I was curious if there was something that prevented this in Haskell, beyond a design choice.
- mrkeen 2y agoHaskell/GHC tells you what the types are. Proper, global, most-general type inference. Not that local inference crap [1] that the sour-grapes types will say is better. You lose this ability if you start letting the compiler decide that `Int` is as good as `Maybe Int`. Or if an `Async (Async String)` may as well be an `Async String`. That's not to say it's not easy to transform (just a few keystrokes), but explicit beats implicit when it comes to casting (in any language). [1] Does this work? var x = 1 == 2 ? Optional.of(2L) : Optional.empty().map(y -> y + y); // Operator '+' cannot be applied to 'java. lang. Object', 'java. lang. Object' How about Optional<Long> x = 1 == 2 ? Optional.of(2L) : Optional.empty().map(y -> y + y); // Operator '+' cannot be applied to 'java. lang. Object', 'java. lang. Object' or even Optional<Long> x = 1 == 2 ? Optional.of(2L) : Optional.empty().map((Long y) -> y + y); // Cannot infer functional interface type No, we needed Optional.<Long>empty() instead of Optional.empty() to make it work
- magicalhippo 2y ago> letting the compiler decide that `Int` is as good as `Maybe Int` I was thinking more like explicitly telling the compiler that an implicit cast is OK, in other languages done by implementing the implicit cast operator for example. edit: but if I understood you correctly, Haskell just doesn't support any implicit casting?
- mrkeen 2y agoIt will do some wrangling of literals for you, as long as it can unambiguously decide on an exact type during type-checking. If no other info is given, it will treat `3 + 3` as Integer + Integer (and emit a compiler warning because it guessed the type). With `(3 :: Int64) + 3`, the right 3 will resolve to Int64. Same if you swap their positions. `(3 :: Int64) + (3 :: Int32)` is a compile error. "Text literals" can become a String, a Text, or a ByteString if you're not explicit about it. > implicit cast operator Wouldn't that make it explicit?
- magicalhippo 2y ago> Wouldn't that make it explicit? No, the casting is still done implicitly. That is I can make the following compile fine in Delphi if I add an implicit cast operator to either Foo or Bar: Foo x := Foo.Create(); Bar y := x; If neither of them have a suitable implicit cast operator defined, it will of course fail to compile. Just an example, nothing unique about Delphi. You can see an example of the operator definition here[1]. [1]: https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Operator_Overloading_(Delphi) https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Oper...