On 11/07/2013, at 6:16 PM, <o...@okmij.org> wrote: > > I'd like to emphasize that there is a precedent to non-recursive let > in the world of (relatively pure) lazy functional programming.
So what? You can find precedents for almost anything. I could even point you to a lazy mostly-functional language with assignment statements in which an identifier occurrence may refer to two different variables in the course of execution. Having a precedent doesn't mean that it's a good thing. > The programming language Clean has such non-recursive let I am familiar with Clean and used it quite a bit for several years. My experience with that Clean idiom is *WHY* I hate this usage and love monads. > > Let me point out the latest Report on the programming language Clean > http://clean.cs.ru.nl/download/doc/CleanLangRep.2.2.pdf which I already have. If the Clean developers hadn't decided to concentrate on Windows, leaving the systems I used to wither, and if they hadn't made fairly massive changes to the language that broke all my code, it's _possible_ that I might eventually have come to regard this style as acceptable. > It seems the designers of Clean have the opposite view on the explicit > renaming (that is, sequential numbering of unique variables). That is so. If that's what you want, you know where to find it. Like I said, precedent is not proof of goodness. > > readchars:: *File -> ([Char], *File) > readchars file > # (ok,char,file) = freadc file > | not ok = (,file) > # (chars,file) = readchars file > = ([char:chars], file) This is *PRECISELY* the kind of stuff that I find confusing. If they would just *NUMBER* the states so that I can tell what is happening when, I would be so much happier. > The code uses the same name 'file' all throughout, shadowing it > appropriately. Clean programmers truly do all IO in this style, see > the examples in > http://clean.cs.ru.nl/download/supported/ObjectIO.1.2/doc/tutorial.pdf > > [To be sure I do not advocate using Clean notation '#' for > non-recursive let in Haskell. Clean is well-known for its somewhat > Spartan notation.] I wouldn't call Clean Spartan. Clean syntax is elaborate. It achieves brevity not by avoiding keywords but by using punctuation marks for them, as in [t] vs [!t] vs [|t] -- does it leap to the eye that [t] is lazy, [!t] is head strict, and [|t] is strictness-polymorphic? -- and the very important distinction between a *function* f x = e and a *macro* f x :== e. (There's a reason why the higher-order list processing 'functions' are actually 'macros'. See page 109 of the report. There's precedent for a LOT of things that I don't want in Haskell.) > State monad is frequently mentioned as an alternative. But monads are > a poor alternative to uniqueness typing. In this particular case, uniqueness typing is an utter red herring. People are advocating state monads JUST TO HIDE THE WIRING, not to get the effect of destructive assignment. I *agree* that uniqueness typing is a fine thing and recommended it to the Mercury developers, who adopted it. I don't care whether they are called monads, state combinators, or weeblefretzers. What I care about is that that - the states are HIDDEN from the human reader and - they are AUTOMATICALLY wired up correctly for the author. Suppose we have # (x,s) = foo s # (y,z) = bar x s # (z,s) = ugh x y s where my finger slipped on the s key in the second line and pressed the z key instead. Precisely BECAUSE the variable name is the same each time, nobody notices, not the compiler, not you, not me. The program just goes wrong. With numbered variables, let (x,s1) = foo s0 (y,z2) = bar x s1 (z,s3) = ugh x y s2 in ... the compiler notices that s2 isn't defined. With suitable combinators, foo >>= \x -> bar x >>= \y -> ugh x y ... nobody can make the mistake in the first place, because the state variable isn't _there_ to get wrong. > > Why Clean is relatively unknown? Well, why is Amiga? Clean is relatively unknown because - they started in the Macintosh world, and when they provided a compiler for the Unix world, they did not port their "modern" graphics and I/O library to it. So you could never write a program that would run on Macs and other things. - they then abandoned the Macintosh world for Windows. The Mac IDE was killed off; there is now an IDE for Windows but not MacOS or Linux. - other major features remain Windows-only - the change from Clean 1.3 to Clean 2 was huge, like I mentioned above, none of my code survived the change, and there was at that time no conversion program - the available books about Clean are way out of date, several drafts of other books remain incomplete. - the documentation (like the Report) has always been rather amateurish and incomplete. Certainly compared with the Haskell documentation. - there is nothing to compare with the Haskell Platform. - The language was originally called *Concurrent* Clean, running on a network of Macs. But the concurrency support was dropped. There are rumours of ideas of plans to do something about this some day, but there is nothing like the concurrency support that Haskell has *right now*. If I had to write something on a Windows box, I would definitely think about Clean again. And then I would use F#, because I can run F# on my Mac as well, and it has a great deal more in the way of library support. For what it's worth, > let x = 1 in - let x = x+1 in - let x = x+2 in - x;; prints val it : int = 4 in the F# interactive system, but > let x = 1 in - let x = x+1 in - let x = x+2 in - x;; prints "Duplicate definition of x" at the second line. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe