Live data from Hacker News

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

np.reddit.com

161–170 of 172 posts

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

#161
post #57

For me the value of typed functional programming has been it's ability to encode business logic in to the type system and thus validate some of my logic at compile time.

Something about putting business logic in a type system irks me more than someone building another compiler or database in Haskell.

Business logic relies so much on run-time values that (IMO) using data and predicates is a better fit.

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

#162

Earlier quoted context omitted.

> You can't because you don't know where it came from Maybe that's a particular language constraint? In general exceptions have a stack trace and it's evident where an exception came from. At least in my experience exceptions don't have to be handled unless or until they're disruptive. If you have a scheduler or task processor code that needs to run continuously then you're going to have robust exception handling, bu…

My problem with exceptions, is it's generally not possible to tell which exceptions a given function might throw (especially problematic with nested dependencies). Thus even if there was a condition hat you could handle you might not know it was possible (until you hit the bug in production!) Result/Maybe types are awesome, because you just don't get unexpected runtime exceptions due to programming error. You only ge…

> it's generally not possible to tell which exceptions a given function might throw

That's a valid concern. I've seen attempts to document the custom exception types that classes can throw but it's never discoverable. It's compounded by the fact that uncaught exceptions bubble up.

I don't know that most people would sift through all the possible exceptions and write selective catch blocks to handle them. I think in general they will either catch all exceptions or none, if or until they need to handle a specific scenario that presents itself in production.

My perspective though is primarily of LOB Apps or Integrations and not widely consumed public code or apps.

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

#163
post #42

Earlier quoted context omitted.

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

In my experience, the trick is to remove `using Linq` from the entire project.

As someone who has had a mild case of Linq jealousy for some time, I’m curious what makes you averse.

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

#164

Earlier quoted context omitted.

> 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 chang…

No. No matter how much you dress it with words, technology is not magic. Monads are not magic. Haskell is not magic.

If your data and/or problem is modeled as "if 0 then N/A" no amount of "human nature implicitly explicitly transformed" will help you.

Dealing with non-existent data as opposed to "value = 0" is just as natural in Java, C++ or Javascript as it is in Haskell. And yet, that didn't help.

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

#165
post #72

Earlier quoted context omitted.

The problem with loops is that they are too powerful. They can do almost anything. The functions map and filter are nice and restricted. If you want more power, you use eg a fold. And if you need even more power, you write a new recursive function. So a quick look at the code will tell you what to expect.

Personally I've found that although this argument sounds good in theory, in practice I don't find loops harder to read than chains of combinators.

Which languages are you reading them in?

For me the argument holds in practice as well. I'm mostly reading my combinators in Haskell, and the loops in Python or some curly brace language.

If you use a general purpose combinator like mapAccumL that has almost as much power as a loop, you don't get that much extra readability compared to the loop.

It's still a bit better, because that combinator still has to process one element of your list for each run through it's "body"; and it clearly warns you by it's very name that it's not just a filter or map, so there's less possibility of confusing it for something simpler.

And, of course, not all loops are created equal. When applicable, for-each loops are much cleaner than classic C-style for-loops for example.

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

#166
post #69

Earlier quoted context omitted.

In Haskell map someFunction listOfValue if you need an index: map someOtherFunction (zip [0..] listOfValues) Python uses 'enumerate' to similar effect. Not sure if C++ has an equivalent?

You can also use: zipWith someOtherFunction [0..] listOfValues # , since someOtherFunction is likely to be # :: (Int -> Value -> Stuff) rather than # :: ((Int,Value) -> Stuff) . zipIndex f = zipWith f [0..] # is also often useful.

Yes. I wanted to keep things simpler for people who don't speak Haskell; and show off composition of simpler combinators to build more exciting things at the same time.

In eg OCaml you have to use something like zipIndex (but implemented differently) or mapWithIndex, because they don't do lazy data structures by default. (And in eg Python their lazy sequences come with lots of caveats because they are not referentially transparent.)

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

#167
post #91

Earlier quoted context omitted.

> But in Haskell you have, for example, Rational numbers to avoid many such problems. Hey, it's for sure nice to have a rich numeric stack (see also some lisps), but in numeric work "use something else" is very rarely a practical answer to issues with IEEE-754.

Sure, it is, but the thing is that a hugely significant amount of the time I've seen those NaNs happen is because of a lack of understanding/care on the part of the devs, and not because they are doing scientific computing. There seem to be a large disconnect here. A big chunk of people don't need the speed that FP math brings, what they need is exactness. And, for most languages with a C-based lineage, actually corr…

Yes, rational numbers are the better default choice. You should get floats only when you ask for them.

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

#168
post #167

Earlier quoted context omitted.

Sure, it is, but the thing is that a hugely significant amount of the time I've seen those NaNs happen is because of a lack of understanding/care on the part of the devs, and not because they are doing scientific computing. There seem to be a large disconnect here. A big chunk of people don't need the speed that FP math brings, what they need is exactness. And, for most languages with a C-based lineage, actually corr…

Yes, rational numbers are the better default choice. You should get floats only when you ask for them.

Unfortunately, for many languages, its the only real choice (without introducing some new significant dependency!)

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

#169
post #36

Paul Snively (the author of the linked reddit post) also gave a great talk entitled 'Typed FP on the Job - Why Bother?' at LambdaConf a couple years back, that spoke strongly to me: https://www.youtube.com/watch?v=8_HsFrXhZlA > And now you can do the most important thing you can do with any piece of code... stop thinking about it! Go home! Pet the cat! Watch House with the wife! ... I love Friday deployments ... you…

Interesting talk, but does that retry logic really provide me with more confidence about its correctness than equivalent impure code?

Thanks, and good question.

I deliberately didn't go into the specifics about the various typeclasses at play and their laws, and how those are tested. Part of that is just for reasons of time, but the more salient reason is that I wanted to show how those of us who do purely functional programming do it in practice. So if you watched the presentation, you saw that most of my thinking was about "OK, how do I elaborate from the most trivial transformation (do nothing at all) to the one I really want?" And that proceeds compositionally: I transform this value to that value. OK, does that value have the right type? No? What do I need to do to ensure that it does? And the transformation steps have some important properties, like their scope being entirely local. I really tried to emphasize this at the end with `attemptRepeatedly`: my description of each line of the whopping three lines is exhaustive. When I say there's no point in writing a test for it, I mean that literally. There certainly are typeclasses at play, and I briefly talk about the `Catchable` typeclass, and show the ScalaDoc for it, which documents an important law: the relationship between catching ambient exceptions and the algebra provided by `Catchable`. I rely on the other typeclasses and other laws in a similar fashion.

The other thing I think is pretty important is the part where I say "Let's look at cases," because the point there is that I can reason about the code by reasoning about the shape of the data it's manipulating. So if a `step` is an `attempt` of `p` that, if successful, `kill`s the retry `schedule` or, if unsuccessful, logs the exception, I'm still dealing with a `Process` of one element (by assumption that `p` will emit one element). Then `retries` will be a `Process` of 0 to infinity elements, because we put no constraints on `schedule`. So `(step ++ retries)` will be one or more elements, and because `step` `kill`s `schedule` on success, because `retries` is derived from `schedule`, `retries` is also `kill`ed. So `(step ++ retries)` is a `Process` that will emit one or more elements, with the last element being the first successful one, or the last failed element if none of the `retries` succeeds, so we take `last`. Then we just `fold` the failure or value back into a single effect, and we're done.

As I discuss in the presentation, there certainly are questions. What happens if the `schedule` is empty? What happens if the `schedule` is infinite? An attendee in Q & A asked a really good question: was I sure `retries` would wait before the first retry, or was the semantics "try, then wait?" (It really is the former, but that wasn't clear from my recorded REPL session.)

Of course, this isn't very impressive for a three-line example, although I think it's pretty striking that it only takes three lines, each of which can be completely reasoned about independently, to achieve a pretty significant operational goal. The point, though, is we can build entire systems this way, and in fact `attemptRepeatedly` is part of a distributed monitoring system I worked on at Intel Media/Verizon Labs, which is written entirely in this way apart from the monitoring types themselves, which present an imperative API for familiarity's sake (and which we later came to regret).

I hope this helps!

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

#170
post #36

Paul Snively (the author of the linked reddit post) also gave a great talk entitled 'Typed FP on the Job - Why Bother?' at LambdaConf a couple years back, that spoke strongly to me: https://www.youtube.com/watch?v=8_HsFrXhZlA > And now you can do the most important thing you can do with any piece of code... stop thinking about it! Go home! Pet the cat! Watch House with the wife! ... I love Friday deployments ... you…

I'm so glad that struck you! I think a lot of organizations talk about "work/life balance" without really doing anything concrete to make that possible, and I certainly appreciate the irony that this purportedly very abstract, theoretical approach to writing software is, head and shoulders, the most impactful thing to my quality of professional life.
Post reply on HN