Live data from Hacker News

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

np.reddit.com

41–50 of 172 posts

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

#41
post #31

Earlier quoted context omitted.

While it does remove edge cases, the code also becomes more opaque. At least to me, functional style programming seems much harder to read and then reason about.

It takes some time to get used to and change mental model from "program describes step by step what to do" to "program describes logical flow of information". I moved from first camp to the second one somewhere during my adult life. And IMO: Both are valid, sometimes first one is necessary (because that's how the machines actually work), but second one is clearly better most of the time for humans, especially in busi…

There's an analogous switch in algebra from notation like f(g(x)) to something more like X_{GF} (where the _{} indicates subscripting, not written symbols). Note the better left-to-right ordering in the terser system.

It's the same dichotomy; are you thinking of f(x) as an instruction to do f to x, or are you thinking of X_F as what happens when X goes through F?

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

#42
post #34

Earlier quoted context omitted.

I was under the impression that the way C# did generics meant that there was no need to box values. (Unlike Java, which treats all values as objects, even value types.)

Two ways to interpret boxing here: 1 Storing a primitive as a first class object 2 packaging and repackaging data There may be situations where the former is not an issue, but the latter often is. If you don’t have a way to treat filter() as a generator/coroutine it means your traversing one collection and inserting those values into another, only to pass it to map() which iterates again and creates a third. If you’r…

Correct usage of IEnumerable helps a lot, as well as the magic that Linq can do with expressions.

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

#43

Most languages rely on coding patterns for code safety. This is merely a best practice , usually involves writing multiple lines of code, and is merely a convention. Functional languages have many of these patterns already encoded into common functions, like map and fold. As functions their correctness can be considered mathematically proven. Would you rather rely on convention or the compiler? Consider adding on top…

What kind of mathematical correctness are you getting by using FP? The same kinds that the Rust compiler offers?

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

#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 sometimes this revenue growth number is not available. For example, the company may not have existed past year, or perhaps it was not public past year and thus it did not publicly disclose its revenues. When they cannot compute revenue growth for these reasons, yahoo finance will helpfully show revenue growth as "N/A", i.e., not available.

That seems all nice and logical, but I noticed that yahoo finance tended to show that revenue growth was not available for many established public companies for which they should have the data. I looked at it more closely and noticed with shock that if the revenue growth of a company was about 0%, yahoo finance would still show it as "N/A"! So some programmer just decided to use 0 as not available and just erased a lot of useful information from their system. Now when I see a company that has N/A as revenue growth on yahoo finance I have to go and check whether the revenue growth was zero, or it was truly unavailable. As I said -- really annoying.

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, without using an embarrassing hack that deletes real data. But of course Haskell gives you more power than just using Maybe. You can create a type that can encompass all kinds of edge cases and information about them. For example, you can embed a reason why the revenue growth data was not available, if that is the case.

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

#46
post #28

Forget the performance or the fancy memory management stuff, this is one of the best things about Rust: it makes you deal with edge cases by default (while allowing you to write code in a largely imperative or functional-lite style). It's why I think it competes for market share with some of what is currently Java/C# and similar languages. A lot of people who use those languages care about correctness, and Rust is bi…

This is also one of the problems with programming with exceptions. You lean on the fact that an exception will be thrown and just propogate up until it finds something, so the normal mindset of an exception-based programmer is to program for the happy-case and only vaguely think about what happens if it goes wrong. I know, I've written a lot of code in this style for many years myself. In some cases, that's not a pro…

There's also the OTP model, where you have exceptions as well as a robust "something" up there. You don't have to deal with the minutiae, and the pattern (processes (aka, isolated processes) and restarts) lets you deal with known or unknown errors.

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

#47
post #28

Forget the performance or the fancy memory management stuff, this is one of the best things about Rust: it makes you deal with edge cases by default (while allowing you to write code in a largely imperative or functional-lite style). It's why I think it competes for market share with some of what is currently Java/C# and similar languages. A lot of people who use those languages care about correctness, and Rust is bi…

This is also one of the problems with programming with exceptions. You lean on the fact that an exception will be thrown and just propogate up until it finds something, so the normal mindset of an exception-based programmer is to program for the happy-case and only vaguely think about what happens if it goes wrong. I know, I've written a lot of code in this style for many years myself. In some cases, that's not a pro…

This is especially evident in e.g. third-party Python libraries.

For example, say you have a pandas dataframe with a column "foo" and you accidentally try to read column "fooo". Instead of getting a useful exception like "PandasException: Attempted to read nonexistent column 'fooo'", you get a traceback 10 layers deep, terminating in something like "pandas.hashtable.PyObjectHashTable.get_item" which ought to be totally invisible to you, the library user.

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

#48
post #28

Forget the performance or the fancy memory management stuff, this is one of the best things about Rust: it makes you deal with edge cases by default (while allowing you to write code in a largely imperative or functional-lite style). It's why I think it competes for market share with some of what is currently Java/C# and similar languages. A lot of people who use those languages care about correctness, and Rust is bi…

This is also one of the problems with programming with exceptions. You lean on the fact that an exception will be thrown and just propogate up until it finds something, so the normal mindset of an exception-based programmer is to program for the happy-case and only vaguely think about what happens if it goes wrong. I know, I've written a lot of code in this style for many years myself. In some cases, that's not a pro…

> the normal mindset of an exception-based programmer is to program for the happy-case and only vaguely think about what happens if it goes wrong.

I'm not sure that's such a bad thing. Exception handling doesn't mean you should be handling all exceptions, just that you can recover if one does occur. If an exception is 100% relevant to what you're doing then yes absolutely handle it, or even clean up your own state before propagating the exception if you can't. But please don't catch any and all exception to suppress or obfuscate them by wrapping it in another domain specific exception.

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

#49

Forget the performance or the fancy memory management stuff, this is one of the best things about Rust: it makes you deal with edge cases by default (while allowing you to write code in a largely imperative or functional-lite style). It's why I think it competes for market share with some of what is currently Java/C# and similar languages. A lot of people who use those languages care about correctness, and Rust is bi…

Rust forces you to deal with edge cases using very low-order, often Procrustean bed reasoning. This does not mean there are much more powerful higher level ways of doing this. (Pattern matching I got in exchange have made me cry)

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

#50

Most languages rely on coding patterns for code safety. This is merely a best practice , usually involves writing multiple lines of code, and is merely a convention. Functional languages have many of these patterns already encoded into common functions, like map and fold. As functions their correctness can be considered mathematically proven. Would you rather rely on convention or the compiler? Consider adding on top…

What kind of mathematical correctness are you getting by using FP? The same kinds that the Rust compiler offers?

Different, but related. If you call 'map' then you know you're not mutating the values, and you get an output the same size as the input without dropping values, and...

It means you operate on a higher level of abstraction, and that inherently makes reading code faster. Not per line of code, but certainly per functional unit.

Idiomatic Rust tends to use a lot of functional code, and provides all the tools to make that safe. Its map function could mutate the input -- it would be unidiomatic, but certainly possible -- except that, if you don't pass a mutable reference, then you're safe to assume it won't.

Post reply on HN