1. 7

  2. 2

    Partial functions make writing Haskell a lot harder than it should be.

    Writing Haskell would be way harder if partial functions weren’t permitted. Part what Haskell does right is it’s flexible, so that I can choose the level of robustness I want for a particular program. If partial function definitions were removed it would become way harder to do the exploratory programming that eventually leads to that very-reliable codebase everyone loves to tout, since you’d be forced to deal with error handling that really isn’t relevant early on. GHC’s warnings offer a good balance there, I just don’t like the implication that partial functions are an all-around problem.

    1. 2

      Is it really that hard to add undefined for the branches you don’t want to deal with yet?

      I feel like most haskell programmers I know start by just writing down types for functions, leaving all the bodies as undefined (so you can get the types working before you bother writing implementations). With that exploratory style, when you start filling in bodies, you just leave a wildcard case that has undefined as its body to make the function match all input. It seems like relatively minimal work, and makes much more explicit that you are deciding to keep a function only partly defined because you haven’t decided what to do in some of the cases.

      1. 3

        So let’s say you’re developing by gradually adding the full case-selection to a function, and you do it either by leaving off the empty case or adding the explicit undefined. In the implicit version, the compiler warns you so long as the function is incomplete, so it tells you what needs doing and what’s done. In the explicit case, the only warning you’ll get is once you’ve already added all the real cases so that the undefined branch is now redundant, so to tell what’s missing in your code you have to both look through the file to find the = undefined, and then check the compiler warnings to make sure none of those are superfluous.

        Then let’s say you add a new constructor to the type. In the implicit case, you just work through the warnings. If the compiler errors on non-completeness, you’d need to add = undefined to every pattern match to get the thing to compile so you can test along the way, then work back through those to actually implement them.

        Which of these workflows sounds more pleasant to you? It looks to me like requiring case totality is a questionable safety benefit for a definite usability loss.

        If you feel differently, there’s always -Werror.