Live data from Hacker News

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

np.reddit.com

121–130 of 172 posts

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

#121
post #78

Earlier quoted context omitted.

> You can create a type that can encompass all kinds of edge cases and information about them. This is not unique to functional programming languages. Haskell was definitely a trailblazer for this, but plenty of conventional languages support this now with relative ease.

Any language with a type system at all can create a Maybe type. The difference is that failing to handle the None case is a runtime exception in most languages where in Haskel/Rust it won’t compile. I don’t know of any mainstream language that has bolted on that level of verification.

C.

  typedef struct{int filled; union{void* data;} val;} maybe;

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

#122

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

The answer doesn’t necessarily have to be statically known, just ensure that the edge case is handled. computePlane() can return Maybe, where Nothing is returned in the colinear case.

This seems not that different from throwing an exception, except the caller can’t accidentally forget to deal with the colinear case, there must be code to handle the Nothing case.

But perhaps the question you’re asking is “but how can the writer of toPlane() know THEY did the right thing”. There’s of course no solution to logic errors (function subtract(a,b) { return a + b } will get by most type systems, short of having the type system re-encode the function itself, at which point it’s just correctness through redundancy — unless both the type AND function are wrong!).

However, you COULD protect against future people breaking your implementation by doing something analogous time weak_ptr’s implementation and flipping the Maybe to the input vs the output). So for example, you could make a type NonColinearSet, and have the “constructor” take a PointSet, but return a Maybe, so asNonColinearSet takes a PointSet and returns Nothing if the PointSet is colinear, or NonColinearSet if it isn’t. Now you computePlane() function can take a NonColinearSet and return Plane (not Maybe) since it “knows” the input must be valid, so it can ignore edge cases internally, at the cost of the caller having to deal with toNonColinearSet returning Nothing before calling it, since you won’t be allowed to transparent pass the result of asNonColinearSet(pointSet) to computePlane since the types Wong match (Maybe vs. NonColinearSet).

    maybeNonColinear = asNonColinearSet(pointSet);

    case Nothing: alertUserBadDataOrWhatever();
    case Just: return toPlane(maybeNonColinear.value)
Notice in both cases, ultimately the caller must do something in the edge case, which is what you want.

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

#124
post #45

Conversely, it's also one of the biggest pain-points when throwing together a quick prototype.

Then here's where typescript shines. To be able to move fluidly between no static checks of JavaScript and strong-ish type safety of typescript without too much work. Then again, it's not always without hiccups.

That is where I think Flow really shines. Seems to be less hiccups, but that is just my anecdotal experience.

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

#125

Earlier quoted context omitted.

Scala3 and Kotlin.

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 will do exhaustive checks in a `when` block when it is an expression. You can add a `.let { }` at the end of the when statement if you want to enforce this and not really return anything.

    sealed class Communication
    data class Email(val emailAddress: String) : Communication()
    data class Shouting(val preferredName: String) : Communication()
    object HiveMind : Communication()

    fun exhaustiveWhen(comm: Communication) {
        // not exhaustively checked (will compile)
        when (comm) {
            is Email -> println("sending email to ${comm.emailAddress}")
        }

        // *is* exhaustively checked (error at compile time)
        //  must add HiveMind or 'else' branch
        val result = when (comm) {
            is Email -> println("sending email to ${comm.emailAddress}")
            is Shouting -> println("HELLO, ${comm.preferredName}!")
        }

        // *is* exhaustively checked
        when (comm) {
            is Email -> println("sending email to ${comm.emailAddress}")
            is Shouting -> println("HELLO, ${comm.preferredName}!")
        }.let {  }
    }

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

#126
post #35
post #29

Earlier quoted context omitted.

This isn't particular of Rust. Nim also forces you to deal with all possible branches of a case statement. I'm pretty sure other languages do so as well. This is just basic type safety stuff.

plenty of other languages do so, but it's both unfairly diminishing to the parent & questionably correct to refer to it as "basic type safety stuff"

No, it is basic. If you have a sum type, and you have no defined behaviour for one of the terms of the sum type, your code is not type-safe and a language that aspires to "basic type safety stuff" should at least issue some kind of error about it. In a putatively statically-typed language (ie one that does type checking at compile time), you'd expect that error to happen at compile time.

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

#127
post #78

Earlier quoted context omitted.

Any language with a type system at all can create a Maybe type. The difference is that failing to handle the None case is a runtime exception in most languages where in Haskel/Rust it won’t compile. I don’t know of any mainstream language that has bolted on that level of verification.

C. typedef struct{int filled; union{void* data;} val;} maybe;

How does that fail at compile time if you try to read a value when there is none?

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

#128
post #27

Earlier quoted context omitted.

Yes, apparently, there is a -Wswitch statement in gcc, which looks quite similar, maybe I have used too old compilers... > Warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. (The presence of a default label prevents this warning.) case labels outside the enumeration range also provoke warnings when this option is used (even if ther…

The issue with -Wswitch (and thus -Wall) is that the presence of a default case suppresses the warning. Which you may not want, if you need non-default behavior because you're adding a new value! There's -Wswitch-enum (not turned on by -Wall or -Wextra) that stops this being suppressed. This is good, though the (possible) list of cases that are well-handled by the default at the end of switches that just fall-through…

A default case supreses the warning in Haskell too, there is no other option.

The real problems with C enums aren't about matching completion, they are that:

- There is no guarantee that a variable value is in the enum range;

- A C (or Java, or C#) enum is a very poor type and can not represent all the data that a Rust enum carries. Developers usually use them with union types to solve that problem, but then there aren't any warnings for most problems anymore.

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

#129
post #60
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.

What's specifically functional about this advantage. Can't you encode the buisness logic into types in non-functional languages as well?

On practice, no you can't. At least today.

But it may be a very interesting question for a researcher.

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

#130

Earlier quoted context omitted.

C. typedef struct{int filled; union{void* data;} val;} maybe;

How does that fail at compile time if you try to read a value when there is none?

Some of Dawson Engler’s work helps solve this problem, starting around [1]. In that, he shows us how to write custom compiler rules in a high-level language. These rules are sufficient to enforce that maybe type. In another paper, Engler (or one of his several talented students, can’t remember now) shows us how to automatically infer many of these rules.

[1] https://web.stanford.edu/~engler/mc-osdi.pdf

Post reply on HN