Live data from Hacker News

Notes on Haskell: What's Wrong with the For Loop

notes-on-haskell.blogspot.com

41–50 of 59 posts

Re: Notes on Haskell: What's Wrong with the For Loop

#41

That word, closure. You keep using it, but I do not think it means what you think it means. A closure is an runtime structure used to implement static scope of locally-defined first-class functions. Closures allow locally-defined functions to "remember" variable bindings in their enclosing scope. Beside that you can implement this feature WITHOUT closures (e.g. source rewriting), none of the examples presented actual…

Yes, this has been one of my pet peeves for a while too. Everybody: a closure, as the parent says, is an implementation construct. It is not something you can find in your source code. The syntactic construct -- the thing you write in your code -- is called a lambda expression . Not a "lambda function", and not a "closure"! Lambda expressions are to closures as `new' expressions are to instances: a lambda expression…

> Instances and closures are closely related: an instance is a piece of state with several operations that can be invoked on it, while a closure is a piece of state with one operation that can be invoked on it.

I would go further, and say that they're equivalent—that "one operation" can be a dispatch function:

    def make_object
      x = 5
      lambda do |m|
        case m
        when 'increment'
          x += 1
        when 'decrement'
          x -= 1
        when 'get'
          x
        end
      end
    end

    o = make_object
    o.call('get')       # => 5
    o.call('increment') # => 6
    o.call('decrement') # => 5

Re: Notes on Haskell: What's Wrong with the For Loop

#42

Colour me stupid, but in the article it gives this code as having some horrible hard to find bug: String s = ""; for (int i = 0; i Now, as soon as I looked at that I immediately thought "well, they're not putting anything in between the params when they concatenate them", e.g. I would expect to see: s += array[i] + "\t"; (or a comma or newline instead of a tab) My next thought was "what happens if there are no args?"…

Why are you looping over array, when you are checking over the bounds of args? Shouldn't it be s += args[i]; Normally, you loop over the thing you're checking the bounds for. The fact that this has been sitting on HN front page all day and there's no single, satisfactory answer (I mean, is this a satisfactory answer?) is to me a Key Failure of the for loop. For loops just don't capture very much in terms of semantics…

Well put.

I see the comments here which argue about what a closure really is (and there is a lot of conflicting info out there. Even Douglas Crockford explains it differently than the comments I've seen on this article) when the point of the article is that for loop are an anti-pattern - exactly as you say.

This realization really hit home for me when I started using Clojure and kept trying to figure out how to do a for-loop. Once you wrap your head around map, reduce and filter, all of a sudden you realize how expressive a programming language really can be.

Re: Notes on Haskell: What's Wrong with the For Loop

#43

That word, closure. You keep using it, but I do not think it means what you think it means. A closure is an runtime structure used to implement static scope of locally-defined first-class functions. Closures allow locally-defined functions to "remember" variable bindings in their enclosing scope. Beside that you can implement this feature WITHOUT closures (e.g. source rewriting), none of the examples presented actual…

Yes, this has been one of my pet peeves for a while too. Everybody: a closure, as the parent says, is an implementation construct. It is not something you can find in your source code. The syntactic construct -- the thing you write in your code -- is called a lambda expression . Not a "lambda function", and not a "closure"! Lambda expressions are to closures as `new' expressions are to instances: a lambda expression…

Your insistence on a specific meaning for the words ignores how words are actually used: overloaded based on context. If I call these things 'closures', you understand I'm talking about the 'lambda expressions' and not the implementation construct.

  class Foo
  end
There, a class object. Oh sorry, an object is an implementation construct; what you have there is an expression that produces an object... If I see the Eiffel tower, I say: look, the Eiffel tower. Not: look, an image of the Eiffel tower, with some details obscured by clouds and smoke and without considering any of the construction details and history that are an essential part of the Eiffel tower. For all practical purposes of communication, it's the Eiffel tower.

Re: Notes on Haskell: What's Wrong with the For Loop

#44

Earlier quoted context omitted.

I rarely use for loops in Python. Most of the time I use list comprehensions, which are much more terse and expressive than loops and, at least to me, are easier to parse than map/filter/reduce functions.

Funny, that. List comprehensions are actually sytactically and semantically more difficult than folds, modulo your logic. Honestly, I suspect the Haskell style and the curious Python cultural disdain for real lambadas have far more to do with your confort than any absolute metric of comprehension.

Anyone who has disdain for real lambadas just doesn't know what they're missing: http://www.youtube.com/watch?v=5AfTl5Vg73A

Re: Notes on Haskell: What's Wrong with the For Loop

#45
post #28

"But it does highlight the key failing of for loops: they conflate three separate kinds of operations -- filtering, reduction and transformation." There's actually four kinds of operations: filtering, reduction, transformation, and good Lord man what the hell are you doing with the loop index? did it just go negative? It did! Why? And it still works‽ , which is actually quite hard to simulate with functional programm…

For the WTF kind of operation, 'while' loops are much more idiomatic - generally, you'd want to use a for loop for things that are minimally recursive (i.e., where you can see, before starting the loop, that the loop body will be executed N, or len(L), or whateverNumberItIs times).

Re: Notes on Haskell: What's Wrong with the For Loop

#46

Earlier quoted context omitted.

Yes, this has been one of my pet peeves for a while too. Everybody: a closure, as the parent says, is an implementation construct. It is not something you can find in your source code. The syntactic construct -- the thing you write in your code -- is called a lambda expression . Not a "lambda function", and not a "closure"! Lambda expressions are to closures as `new' expressions are to instances: a lambda expression…

Your insistence on a specific meaning for the words ignores how words are actually used: overloaded based on context. If I call these things 'closures', you understand I'm talking about the 'lambda expressions' and not the implementation construct. class Foo end There, a class object. Oh sorry, an object is an implementation construct; what you have there is an expression that produces an object... If I see the Eiffe…

That's not a fair example. There are languages that have lambda expressions but not the lexical scope that requires closures, whereas there are no languages that have class definition expressions but not classes.

Given there is a meaningful distinction to be made, insistence on accurate terminology becomes a lot more reasonable.

Re: Notes on Haskell: What's Wrong with the For Loop

#47
post #40
post #36

Earlier quoted context omitted.

After reading this, I got to wondering if I could hijack sum into joining lists. My first attempt didn't work: sum([ range(n,n+5) for n in range(5) ]) just gave me "TypeError: unsupported operand type(s) for +: 'int' and 'list'", which didn't make a lot of sense. Where did I pass an 'int' by itself? Well, according to the help, sum takes a second argument: a starting value, which defaults to 0. So, I wondered, what i…

That's actually quite clever.

Thanks, but I got a little update: it won't work on strings.

The help says as much, in fact. Actually, what it says is, "Returns the sum of a sequence of numbers (NOT strings)," which I think is meant to imply it won't parse numbers out of strings, but in theory, sum should be able to concatenate strings as easily as it does lists, with the right start argument. Instead:

  >>> sum([['room315'], ['room2']], [])
  ['room315', 'room2']
but:

  >>> sum(['room315', 'room2'], '')
  TypeError: sum() can't sum strings [use ''.join(seq) instead]
Say, what???

I'm not sure, but I think sum is specifically watching for strings, and throwing a TypeError if it finds one. Otherwise, if it's simply using the + operator internally, as its list-handling behabior seems to imply, it should mash strings together just as happily! Oh, well. The join function is the right one for that job. It just seems a bit of wasted effort, to me.

Re: Notes on Haskell: What's Wrong with the For Loop

#48
post #36
post #7

Earlier quoted context omitted.

I've gotten the impression that there are, in a sense - in python, list comprehensions are usually preferred over for-loops in places where you would use map and filter, and the most common use cases for fold/reduce are covered by functions like sum and join. List Comprehensions also tend to be preferred over higher order functions, perhaps for readability, but also, in python 3, the higher order functions return gen…

After reading this, I got to wondering if I could hijack sum into joining lists. My first attempt didn't work: sum([ range(n,n+5) for n in range(5) ]) just gave me "TypeError: unsupported operand type(s) for +: 'int' and 'list'", which didn't make a lot of sense. Where did I pass an 'int' by itself? Well, according to the help, sum takes a second argument: a starting value, which defaults to 0. So, I wondered, what i…

I've seen it used for a long time. The only problem with it is the quadratic time complexity: it's equivalent to ((N0 + N1) + N2) + N3 ... so you copy the same elements over and over again as the sum builtin doesn't know to use anything but the + operator to build each element. (I vaguely recall some discussion about making it more efficient on sequences of sequences).

A more efficient version would be: def sumseq(l): r = []; map(r.extend,l); return r

which would also work on any type of sequence as input, even if mixed. A quick test shows the quadratic time complexity being noticeable at about 128 items, where sumseq is 10x as fast and 1751x as fast at 16384 items.

Re: Notes on Haskell: What's Wrong with the For Loop

#49
post #28

"But it does highlight the key failing of for loops: they conflate three separate kinds of operations -- filtering, reduction and transformation." There's actually four kinds of operations: filtering, reduction, transformation, and good Lord man what the hell are you doing with the loop index? did it just go negative? It did! Why? And it still works‽ , which is actually quite hard to simulate with functional programm…

I can top that mine went up to 17 and then jumped to 200 for no obvious reason(some sort of memory bug where memory in a different part of the program overlapped with the loop variable).

Re: Notes on Haskell: What's Wrong with the For Loop

#50
You can execute loop in your head just by reading it line by line. Token by token. With other solutions you need to know other things to determine what goes inside and believe it is actually what you want it to be. Loops ar flat, explicit and versatile. I think that is the reason behind their popularity.
Post reply on HN