Live data from Hacker News

The general value of typed functional programming lies in leaving no edge cases

np.reddit.com

111–120 of 172 posts

Re: The general value of typed functional programming lies in leaving no edge cases

#111
I came to a similar insight by the corollary: a sound type system makes the edge cases obvious. When we make the type of a partial function total by introducing an optional value as a result there's an opportunity to develop an intuition that this is going to make my code harder to reason about. Assuming I fix all the warnings about incomplete pattern matches I know that users of this code will have to handle all of the edge cases I'm introducing. Therefore I might take another approach and introduce a type as my pre-condition: the type of non-empty lists. You can't even call my function unless I can be assured there's at least one element in the input. I haven't even had to look at the implementation to reason about my code yet.

    head :: [a] -> a
    -- versus
    saferHead :: [a] -> Maybe a
    -- versus
    safeHead :: NonEmpty a -> a

The first function is partial because we'll get an exception if we give it the empty list.

The second function is total but annoying to use because we're telling all the code that uses the result to check for two cases (it's an error not to).

The last one forces the responsibility on the caller to provide a non-empty input.

That was probably one of the more frustrating aspects about learning to program Haskell as someone who has been programming for more than fifteen years when I started. It revealed to me in stunning detail all of the edge cases that almost every other language I've used actively hides from me.

It doesn't absolve you of having to think about edge cases: even Haskell throws run-time exceptions. However it does give you tools to think about many of those edge cases up-front and in a direct way.

Update Added a trivial example to demonstrate "partial," etc.

Re: The general value of typed functional programming lies in leaving no edge cases

#112
post #75

Earlier quoted context omitted.

Also Java has Optional and C# has Nullable .

That's not important in practice. What's important is that null infects all reference types in Java and C#, whether you asked for it or not. Just today I've spent a half an hour looking for a null dereference error - which the type system should've warned me of but didn't. The sad fact is, neither Java nor C# are fixable, because no new feature will fix the broken, null-unsafe code already written. All because of thi…

> was blindly copied over from C++.

From C! AFAIK C++'s references can not be null!

Re: The general value of typed functional programming lies in leaving no edge cases

#113

Earlier quoted context omitted.

Haskell is so much better, and you would learn that with about 5 minutes learning about the number types

Haskell's intro page starts with the infamous minimalist quicksort, which mishandles NaN! https://wiki.haskell.org/Introduction#Quicksort_in_Haskell

How should it handle NaN? It's not clear where an incomparable value should go when sorting.

Re: The general value of typed functional programming lies in leaving no edge cases

#114

Earlier quoted context omitted.

You mean Scala 2. And likely even Scala 1 had this. (Scala 3 is still in development). But Kotlin? Since when does Kotlin have pattern matching with exhaustive checks? Also it does not have an `Maybe a` / `Option[A]` type out-of-the box.

Kotlin distinguishes between nullable and not-null references, which is an alternative to the maybe type. It serves roughly the same purpose, to replace runtime errors with compile-time verification that you haven't missed a corner case.

that prevents you from assigning null to a non-nullable reference. does it also error if you dereference a nullable reference without first checking if it's null?

Re: The general value of typed functional programming lies in leaving no edge cases

#115

I came to a similar insight by the corollary: a sound type system makes the edge cases obvious. When we make the type of a partial function total by introducing an optional value as a result there's an opportunity to develop an intuition that this is going to make my code harder to reason about. Assuming I fix all the warnings about incomplete pattern matches I know that users of this code will have to handle all of…

100% that's a big part of it (although there are others).

Although if someone doesn't know haskell, then the above notation for functions getting the first element of a list is probably not of much value to them.

Clearer would be:

  char  head(List x);
  char? saferHead(List x);
  char  safeHead(NonEmptyList x);

Re: The general value of typed functional programming lies in leaving no edge cases

#116

Earlier quoted context omitted.

Haskell is so much better, and you would learn that with about 5 minutes learning about the number types

Haskell's intro page starts with the infamous minimalist quicksort, which mishandles NaN! https://wiki.haskell.org/Introduction#Quicksort_in_Haskell

I mean, this is a whole different thing, and I legitimately hate that "algorithm".

But you have to understand that the whole situation is a bit complicated. The thing though is that Haskell gives you possible ways to handle those complications.

Re: The general value of typed functional programming lies in leaving no edge cases

#117
post #2

Edge case removed: for i=0 to 10 {print(a[i])} vs for x in a {print(x)} With functional programming it gets even better: a.filter {}.map{print} Pseudo code, of course. I list several “functional“ examples in Swift here: https://github.com/melling/SwiftCookBook/blob/master/functio... Functional programming is also a higher level language. map, reduce,filter, flatten, flapMap, drop, take, zip, ... Learn the concepts in…

I program mainly in C++, and I often start off writing things as: for (auto x : someContainer) { //do something with x } But inevitably, I end up needing either an iterator pointing to a particular item at the end, or I need an index to pass to some other function, and this style makes that impossible. Perhaps it's just the domain I work in, but even after years of trying to make this work, it still only works about…

http://p3rl.org/each

while (my ($index, $value) = each @list) { ... }

https://docs.raku.org/routine/kv#class_List

for @list.kv -> $index, $value { ... }

Re: The general value of typed functional programming lies in leaving no edge cases

#118
post #44

I am not sure this is the only value, but it is generally true. And this is one of the great advantages of haskell. By the way, now that I know some haskell, I see this edge case sloppiness all the time and it is really annoying. For example, here is something that annoyed me just recently. You go to yahoo finance and there they will show you the revenues of a company as well as the revenue growth from past year. But…

> This is of course a textbook case for Haskells Maybe concept. You can have a type that is a Maybe Int, and that means it have a value or it can be Nothing. Thus, you encompass the edge case of not having the value available If you encompass it this way. Literally nothing stops you from encoding this behavior in Haskell. Because the behavior you described is *if revenue is equal to zero, display it as N/A". No magic…

No, but it's the difference between implicit and explicit stupidity. All of us do implicit stupidity all of the time - it's human nature (or more accurately a side effect of working in a difficult field). When transformed into a choice between explicit stupidity, or doing things the right way, we instead usually choose to to do things the right way -- or at minimum do it the wrong way to test something out then change it to the write way. Being explicit is what makes that change likely to happen, rather than just be ignored.

Re: The general value of typed functional programming lies in leaving no edge cases

#119

Earlier quoted context omitted.

Many people have their compilers set to enforce these things, and many of us go a step further and make our compiler warnings into errors so it’s impossible to build a program with these errors. That’s very commonplace, and C++ does it just fine. Missing cases in enums and at least 100 other very common matters can be checked at compile time in C++, the only difference is that it’s not the default as it is in some ot…

Enums are no substitution for sum types, though.

The comment I was responding to was not about the functionality of a sum type, but rather the compilation errors from leaving out a case. Those are two different matters.

Re: The general value of typed functional programming lies in leaving no edge cases

#120
I wonder, aren't there problematic edge cases that depend on the data? For example, if you are computing a plane from a given set of points, there may be an edge case where the points are collinear. Assuming you always need to produce a valid plane, this would require some numerical analysis and regularization. Or is the answer to define some new type system that captures the non-collinearity? If so, it seems like the costs of enforcing that could overwhelm things...
Post reply on HN