3 ms·
Disclaimer: I love Go and the more I learn about Haskell the more I love it, as well. So is the distinction here that, basically, you push the distinction betw
by wonderzombie 14y ago
Disclaimer: I love Go and the more I learn about Haskell the more I love it, as well.
So is the distinction here that, basically, you push the distinction between a "nothing" and a "something" down into the language layer? IOW, the `if isJust mx` is the programmer trying to reason about a type, whereas `case mx of` is delegating that reasoning to the compiler/language?
In general I think that's a good principle, but at least in this example I don't quite grok why `if isJust mx` is out-and-out unsafe. Maybe this is just because the (heh) Maybe example is too simple to illustrate the unsafeness.
It does seem more error prone in practice, in terms of engineering & maintenance (read: more likely to lead to bugs). `isJust mx` means you are methodically separating out the verification of what type it is from the access and usage of that type, and since this is all happening at the program layer, you've got to keep the assumptions in your `if` consistent with the assumptions of your type. Conversely the `case of mx` statement leverages the type system to do the work for you.
I'll try to put it another way: the code inside your `if isJust` clause is not semantically related to the clause itself except in the most superficial way. However, with `case mx of`, those clauses are inextricably related since you've (again) pushed the semantics of checking the type and unboxing it down a layer, into Haskell.
Am I anywhere close?
- Peaker 14y agoI may have been slightly misleading if I implied "isJust" is unsafe. It is perfectly safe. What's unsafe is "fromJust" which crashes at runtime if the Maybe value is in fact a Nothing. "isJust" is code-smell because it means you're likely to need a "fromJust" later. The problem is: What if the condition is changed later? What if you use "fromJust" in the else branch? What if the code is moved around outside of the condition's scope? The above is meant to illustrate that the "isJust/fromJust" anti-pattern is out-and-out unsafe. You get no compile-time assurances. If you avoid "fromJust" altogether (and equivalent constructs, of course), you have a 100% guarantee that you will not crash from expecting a Just where there's a Nothing (IOW, nil dereference). Additionally, "Just" and "Nothing" are data constructors (can be viewed as value tags) within the Maybe type, they are not "types" themselves. Except for these points, I think you are generally describing it correctly. This kind of thing (avoiding boolean blindness) as well as a few more safety nets in Haskell is the reason lots of Haskell code is said to Just work once it compiles.
- wonderzombie 14y agoOK, yes, I can see how `fromJust`, more specifically, is the unsafe part. You're dereferencing a pointer which is probably non-nil but the compiler can't tell you because you've insisted on checking it manually rather than communicating your intent to the compiler more directly. So when you say "avoid fromJust," the alternative in practice is to use pattern matching, yes? The example you used above was a case statement. A guard clause is another obvious one, as are additional clauses (?) in a function.
- Peaker 14y agoThere are many alternatives to fromJust. They are all essentially implemented on top of the safe primitive: pattern-matching. Guard clauses in Haskell are actually boolean conditionals, and are boolean-blind. Safe pattern-matching can be done via the function definition sugar: f Nothing = ... f (Just x) = ... Which is equivalent to a "case". The various functions that work with a Maybe value make it non-tedious to do things. For example, instead of: case mx of Just x -> Just (x + 1) Nothing -> Nothing You can write: fmap (+1) mx Additionally, (>>=), fromMaybe and many other useful functions exist, and they're all based on safe pattern-matching.