Live data from Hacker News

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

np.reddit.com

141–150 of 172 posts

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

#141
post #69

Earlier quoted context omitted.

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…

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.

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

#142

Earlier quoted context omitted.

Exceptions and Maybe types aren't mutually exclusive. They should be used together. Maybe types handle variability that is expected and predictable, like a dictionary not having a certain key; exceptions handle the unexpected situations, like a file handle being closed too early. Maybes explicitly express what the programmer has foreseen, exceptions form a safety net over it. You need both in a wholesome language. Th…

Having used Rust, which almost exclusively uses Maybe types, I have to disagree. The "safety net" introduced by exceptions just hides possible errors, and causes reliability problems that would be entirely avoidable if Maybe types were used. The `?` operator makes propogating errors painless if that is what you want, but at least they're all documented so you have to make a concious chocie to pass the buck on error h…

I don't know: if we really wanted to be 'strict' every integer operation should return a Maybe due to possible overflow, every IO operation also.

That's a lot of possible error to handle! I don't like exception's invisible flow but I think that they are good for 'should never happen' errors.

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

#143

OTOH it's nice to be able to do: try { // 500 lines catch (e) { return 4; }

Often, even functional languages have something similar, whether it's call/cc or something more cutting-edge like algebraic effects. All of these essentially augment the execution environment in various interesting ways, and are enhanced by other features of functional languages like immutability.

(More pithily: try/catch is not inherently non-functional.)

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

#144

Earlier quoted context omitted.

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.

Why is NaN even a concept in modern languages? We don’t have a special “not a string” that all string functions return when they have no useful value to return.

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

#145
post #144

Earlier quoted context omitted.

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

Why is NaN even a concept in modern languages? We don’t have a special “not a string” that all string functions return when they have no useful value to return.

Because it's part of IEEE 754.

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

#146

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…

There's also another option in the middle which is a version that takes a value to return when the list is empty

    headOr :: a -> [a] -> a
which is similar to the Maybe solution but forces the caller to discharge the Maybe immediately rather than letting them potentially clutter up the rest of their code by proliferating the Maybe.

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

#147
post #13

Earlier quoted context omitted.

The problem in my domain, games, is the frequent boxing and unboxing of values when using functional iterator interfaces in languages common to the industry, particulalry C#. It just thrashes the heap and forces often too-frequent gc.

While it may or may not be optimal for you/your field for other reasons, I believe Rust does iterators in a 0-cost, no allocation way and generally generates code equivalent to or better than a hand-written for loop.

There are studios moving to rust, and there definitely is a great amount of interest in rust among my peers because of the 0-cost iterator features. The borrow-checking isn't even a big draw, it's the other features!

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

#148
post #42
post #34

Earlier quoted context omitted.

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.

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

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

#149

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 tried it and indeed, the results involving NaN are... interesting

     quicksort :: Ord a => [a] -> [a] 
  .. quicksort []     = [] 
  .. quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater) 
  ..     where 
  ..         lesser  = filter (= p) xs
     quicksort([sqrt(i)|i [0.0,1.0,1.4142135623730951,1.7320508075688772]
     quicksort([sqrt(i)|i [NaN]
     quicksort([sqrt(i)|i []
Now, just for fun, let's reverse the condition...

     quicksort :: Ord a => [a] -> [a] 
  .. quicksort []     = [] 
  .. quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater) 
  ..     where 
  ..         lesser  = filter (\x -> not(x  not(x >= p)) xs
     quicksort([sqrt(i)|i [1.7320508075688772,1.4142135623730951,1.0,0.0]
     quicksort([sqrt(i)|i [1.7320508075688772,1.4142135623730951,1.0,0.0,NaN,1.7320508075688772,1.4142135623730951,1.0,0.0,NaN,1.7320508075688772,1.4142135623730951,1.0,0.0,NaN,1.7320508075688772,1.4142135623730951,1.0,0.0,NaN,1.7320508075688772,1.4142135623730951,1.0,0.0,NaN,1.7320508075688772,1.4142135623730951,1.0,0.0,NaN,1.7320508075688772,1.4142135623730951,1.0,0.0,NaN,1.7320508075688772,1.4142135623730951,1.0,0.0]
  
The last example will explode with larger values, like [-100..100].

Note, it is actually the first time I tried Haskell. And no, I don't think the language is broken because of that. In fact, it is exactly the behavior I expected.

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

#150
post #144

Earlier quoted context omitted.

Why is NaN even a concept in modern languages? We don’t have a special “not a string” that all string functions return when they have no useful value to return.

Because it's part of IEEE 754.

So? There’s lots of old standards that don’t fit well with modern programming languages, so we abandoned them, or only use the parts that still make sense.
Post reply on HN