Hacker Newsnew | past | comments | ask | show | jobs | submit | Skeime's commentslogin

I think this is because in an imperative language, `reduce` does not actually give you much over a `for item in collection` loop. With `map` and `filter`, you immediately learn something about the result (it's a list of the same length as the original, with each item only depending on the corresponding original item; it's a list containing some of the original elements unchanged and nothing else). This is useful, so `map` and `filter` are good.

With `reduce`, the result could be anything, and in an imperative language, side effects are also possible. So it's just a loop with worse syntax.

(Admittedly, in an imperative language, `map` and `filter` could also have side effects, though I think most people would consider this bad style.)


I think that in every imperative language that offers `map`, `filter`, `reduce`, or similar, the written contract of this API should state that any higher-order function handed to it as an argument must be free from side effects.

I think I’ve seen several language core APIs have this in their contract, e.g. `Stream#reduce` in Java [0] (emphasis mine):

> accumulator - an *associative, non-interfering, stateless* function for combining two values

[0]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/S...


In Rust these specifically take `FnMut`, a function which can update internal/borrowed state, rather than `Fn` which can't easily. In `map` or `filter` you shouldn't rely on the iteration order so that's not often useful – maybe something 'logically' stateless but which needs a mutable connection/threadpool/cache, or eg a counter which is really an ancillary reduction. There's even `inspect` which is explicitly for such side effects. In `fold`, the order is guaranteed and you could use it for a state machine, a fiddly `zip` with other mutable iterators, etc – something you need to perform the reduction, but which isn't really an output, I think you could reasonably write either

    .fold(init, move |acc, x| {…})  // or
    .fold((state, init), |(state, acc), x| {…}).1

> I think that in every imperative language that offers `map`, `filter`, `reduce`, or similar, the written contract of this API should state that any higher-order function handed to it as an argument must be free from side effects.

Does the written contract for for-loops specify this as well? Because that's the obvious alternative for a reduce that an imperative programmer would reach for: a for-loop with the programmer managing the accumulation manually.

I also don't see why a reduce should be side-effect free. There's nothing wrong with having a type def't for reduce be

    base.data.List.foldLeft : (b ->{e} a ->{e} b) -> b -> [a] ->{e} b
Where {e} indicates a side effect. Here, the reducer can have side effects, and those side effects propagate to the result of the fold/reduce.

I mean, most of the code that I write would be side-effect free anyway. In an imperative loop, this would also be true except for updating local variables. If this is the case, `reduce` really is the same as a loop over a collection, except that the names for the state passed between iterations come out better. In the `reduce` version, you can name the parameters to the reducer, but often not the return values. As a reader, one needs to connect the return values to the parameters by position.

(Note that by "loop over a collection", I explicitly mean a looping construct that gives the elements of the collection directly, instead of looping over indices and extracting the elements manually.)


Even though it makes print debugging harder, I think it would be better if the language enforced such a contract.

I think what makes reduce less popular is that it takes two lambdas:

- a slightly awkward one that takes a partial result and the next value to produce a new partial result

- one that maps the final partial result to the result

Also, in many languages, when reading the code, you have to skip initialization of the partial result, read the lambda, and then jump back to make sense of the initial values

I think something like awk’s syntax, with BEGIN and END blocks would improve on that. Example of a first go at such syntax (needs work):

  Items.BEGIN
    min = ∞
    max = -∞
    sum = 0
    n = 0
  ITER
    min = Min(min,_)
    max = Max(max,_)
    n += 1
    sum += _
  RETURN
    average = sum / n
    (min, max, average)
Advantages:

- items in the partial results have names, making them easier to understand

- result also is easier to understand

Price paid is wordiness, and you cannot simply write a function name for either of the lambdas.

However, I think the latter only is useful in case the partial result is the final result. There, you can keep

  sum = items.reduce(0,+)
if you want to.

The rectangle case is just choose(w+h, h), with w, h being the width and height, respectively. (Or choose(w+h, w), which is the same.)

Depending on how well you know binomial coefficients, this can also lead you to the dynamic programming solution. After all, for the rectangle case this is nothing but construction of Pascal's triangle by summing two adjacent numbers in a row to get the number below them. If you recognize this, the solution for paths on grids with holes falls out almost immediately.


Lots of formatters also unify things like trailing commas, so it would be slightly more involved than this.


Yes, the dart formatter does that now too. So the sanity check ignores commas and semicolons, which makes it less robust as a sanity check, unfortunately.


I feel like you are describing that the parser is too lenient rather than too picky. It could just require you to always put `let` and `in` on their own lines, in which case the indentation makes sense, I think. It's only when trying to keep more stuff on the same line that the details of Haskell's indentation rules come into play.


Isn't the Macintosh desktop (with Cmd as the modifier for standard shortcuts) older than Windows and Linux desktops? So historically, it's not Apple that deviated but the others?

(I did not do an extensive search into this, so there might be Ctrl-based standard shortcuts that predate Apple.)


Apple moved the Ctrl key around at least a couple times. On the Apple II it was next to the A key, the same as it was on the Xerox Star. The CMD key was a later addition.

At this point, I'd say let history be history. It'd be better to standardize on what most people are using.


Yes, the Cmd key has been around since 1984.


I think modern browsers are actually quite good here. They show a template in the form TT.MM.JJJJ for me (so the German equivalent of MM/DD/YYYY, with the usual order and separator in German). I can just type the date, including the dots if I want (they're just ignored; there would be extra points for moving me to the next component when typing "2.", but the world's not perfect). If I'm confused about the format, or want to see a calendar view, I can click on the calendar icon (also accessible via tab) and select a date there.

For normal date inputs, I really don't think there is a good reason to use anything else. (Possible exceptions I can think of: Selecting date ranges and/or showing extra data about the dates (like daily prices).)


No, modern browsers are horrible at this as they are often ignoring your settings (at least Chrome and Edge on Windows do). They are basing the format entirely on the language instead of the date format configured in your Windows settings. Safari on iOS seems to not have this issue though as far as I can tell.

https://stackoverflow.com/questions/7372038/is-there-any-way...


Mobile keyboards also do have the advantage that they can at least change the label of the button; so writing Submit on the Enter key if it submits.


I am also at the office almost every day because I think it's better for my mental health and food. But I also appreciate that for many, it's different, so actually having the choice individually is nice.


Wouldn't it also be much better to evaluate the Taylor polynomials using Horner's method, instead? (Maybe C++ can do this automatically, but given that there might be rounding differences, it probably won't.)


Fun fact: I looked this up in the online version of the Duden (the predominant German dictionary). It does have an entry "Black Hole" (so the English term!) but not for "schwarzes Loch", which is the normal German term for it.

(In the printed versions, you might need to go to the Universalwörterbuch or so to find the English entry, it might not be in the normal "Die deutsche Rechtschreibung"; I have not checked.)


The Duden is not official since 1996.

Since 2004 the official guidelines for the german speaking countries (Germany, Austria, Swiss, Belgium, South Tirol, Liechtenstein, Romania, Hungary - see this founding document with the list: https://www.rechtschreibrat.com/DOX/wiener_erklaerung.pdf) are covered by the Rechtschreibrat (https://www.rechtschreibrat.com/).

The official german dictionary is here: https://grammis.ids-mannheim.de/rechtschreibung/6774


I wrote "predominant", not "official". And I think that is still true.

Also, from what I can tell using the site, it does not serve as a full dictionary. Rather, it lists the general rules of German orthography (as decided by the Rechtschreibrat) and has some limited tables of special words.


> Duden

Just the name gives me flashbacks to German-lessons in highschool.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: