This is an archived post. You won't be able to vote or comment.

all 180 comments

[–]username223 36 points37 points  (4 children)

Step 0: don't be Jon Harrop.

[–]wingsit 4 points5 points  (1 child)

lets be fair. I am not a fan of him but his books give a good presentation of languages (ocaml and F#).

Also it is his trash comment to other languages that makes people to manly prove the contrary. Without him, no one would explore the dark corner of programming languages.

It takes a bitch for a group to have common focus.

[–]username223 0 points1 point  (0 children)

IME the reaction of other users to The Harrop adopting their language has ranged between "please go away" and "please die in a fire." That self-promoting douche is one of the worst things about OCaml -- even worse than its petulant refusal to do arithmetic -- and he's trying to do the same to F#.

[–]tty2 0 points1 point  (0 children)

Step 1: ???

Step 2: Profit!

Alternate ending:

Step 2: Congratulations! You're not a douchebag!

[–]gregK 27 points28 points  (3 children)

Any one doing a presentation about any Language should take a look at some of the talks from Simon Peyton-Jones (Haskell). This guy knows how his material and how to present it. He always finds the right level and examples for his audience.

Here is one of his talks

[–]davebrk 9 points10 points  (0 children)

First of all you need his enthusiasm...

[–]Nebu 3 points4 points  (0 children)

Then again, this talk is 80 minutes, and the article said that that's about the amount of time you need to present a language. The article was giving advice on what to do in a 20 minute talk.

[–][deleted] 0 points1 point  (0 children)

Any other talk by him that is filmed better? This one films the back of his head or filming him pointing instead of filming the code.

EDIT: n/m found slides in comments http://conferences.oreillynet.com/presentations/os2007/os_peytonjones.pdf

[–]jcreed 10 points11 points  (31 children)

DON'T use a demo based on a mathematical principle (like Fibonacci, factorial, or some other exponent-hugging formula). I ask you, how many developers find themselves writing that kind of code on a daily basis?

DO use a demo based on real-world environments or problems. Use domain types that could have come from a regular line-of-business scenario; my favorite is "Person" ...

I think this represents a cultural difference in the kind of code corporate/industrial/OO programmers vs. academic/functional programmers consider to be "typical". I know that my code --- even when it is not particularly "mathematical" --- far more resembles something like a factorial function than AddEmployeeToPayroll, and so I find the former sort of example much more compelling.

The take-away point is that it's a two-way street: possibly we (the strawman FP fanatics) tend to think your "Person" and "Employee" examples are irrelevant contrived simplistic B.S., merely ginned up to make OO-style programming look like it has enough nails to count as a good hammer, in the same way you don't see the relevance of our factorial examples.

[–]munificent 15 points16 points  (17 children)

academic/functional programmers consider to be "typical". I know that my code --- even when it is not particularly "mathematical" --- far more resembles something like a factorial function than AddEmployeeToPayroll, and so I find the former sort of example much more compelling.

You're already in the choir. There's no need to preach to you. If you're introducing F# to people unfamiliar with functional programming, then relevant examples for an existing functional programmer aren't very helpful.

[–]jcreed 1 point2 points  (16 children)

This is a completely fair point!

Let me confess further: when the article says it is about identifying "structural failures I've seen in several talks attempting to describe F# to the general .NET computing community" it is probably making good recommendations. I bet the general .NET computing community does want to hear "Person" and "Employee" examples.

But I've sat through talks that make the opposite mistake, too. That's all I'm trying to say; that there's some symmetry in the situation: one culture thinks the other culture's examples are "atypical" and weird, and vice-versa. I'm not substantially even disagreeing with the content of the original article.

[–]munificent 5 points6 points  (15 children)

But I've sat through talks that make the opposite mistake, too.

That's entirely valid. When I see academics saying, "What's so great about OOP, we don't get it?" and then you see some guy going "look, I can make objects for my Employees and Accounts!" there's the same disconnect.

An academic or theoretician doesn't care about the specific nouns you're embodying as much as they do the underlying properties of the language and its type system (at least as far as I can tell).

[–]jcreed 5 points6 points  (14 children)

Yes, exactly! Not that there aren't academics into OOP as well, but they're nearly as alien to me as industry OOP people.

The disconnect there is that they (at least the ones I talk to) talk about type systems still, so we have some language in common, but it feels like they believe subtyping is king, and you've got to have it, and it has to be all mixed up in every other feature of the type system.

And I ask, why, why is subtyping so important? I hardly ever feel like I need it in the kind of code I typically want to write. And they say, well, suppose you have Persons and Employees and Accounts...

[–]munificent 2 points3 points  (3 children)

And I ask, why, why is subtyping so important?

I think a big part of the answer is that compared to other ways of building abstractions and composite types (algebraic data types, etc.), subtyping is open-ended. You can build a library of base classes and thousand of users can all extend it easily with their own subtypes, which your library can still easily use.

That's super important in industry where you have large teams, a lot of code sharing, and code that gets used for years and years. Meanwhile, an academic who only works on relatively small programs by himself or with a few others doesn't understand the value of that open-ended-ness.

[–][deleted] 2 points3 points * (0 children)

This is a good point. Interestingly, it's also where the soul-searching the statically-typed FPers have done has paid off the most, as you'll see if you google "expression problem."

[–]jcreed 0 points1 point  (1 child)

This is the story I often hear, but subtyping is still not necessarily essential for all forms of "open-endedness" or "extensibility" or what-have-you.

You can build a library of types and higher-order functions, and thousands of users can all extend it easily by supplying their own functions, which your library can still easily call.

It's not that we academics can't imagine the usefulness of extensibility, and indeed when we collaborate in larger groups and write bigger programs (which we do sometimes, despite the stereotype --- take a look at the rich abstractions used in major compiler and logical frameworks projects) we make things extensible for certain values of extensible --- but not always through subtyping.

Look at emacs, for a non-academic, non-typed, but still FP example: it has hooks everywhere for extensibility. The places where extensibility happen are fairly well-controlled. Emacs's language happens to be a unityped lisp, and so doesn't make any substantial compile-time guarantees, but there's no reason why a type discipline can't describe this form of extensibility.

[–]munificent 1 point2 points  (0 children)

You can build a library of types and higher-order functions

That works too, but I think extensibility through HoF is finer-grained than most business apps would prefer. I think the typical entities a business application deals with are "bigger" than your average academic program, even a fairly large one. Maybe this is just the influence of OOP on thinking, but I tend to think in terms of "OK, I'm defining a new noun, and it has this entire set of capabilities it needs to support" and less "OK, can my new noun be used with this function and this one and this one?" The granularity seems to be a bit bigger, and I think subtyping lends itself to that more than HoFs.

(which we do sometimes, despite the stereotype --- take a look at the rich abstractions used in major compiler and logical frameworks projects)

Compilers certainly are non-trivial, but if you compare a typical enterprise app and the stack of libraries and frameworks it sits on, I think a compiler is still relatively small. It's even more true when you consider how many libraries and frameworks are shared across companies. Literally millions of people are using the Java collection APIs and the .NET base classes. Imagine if those libs were using discriminated unions. Adding a case to one of those unions would break millions of users' code.

Look at emacs, for a non-academic, non-typed, but still FP example: it has hooks everywhere for extensibility.

Emacs is another interesting example. You mention that it "happens" to be dynamically typed, but I think that's an absolute key ingredient in its extensibility. At the same time, it has a high cost. Emacs has a reputation for being slow, massive, and hard to learn. I'm not hating on it, but I don't think it's a great case study in the power of FP. If it was, why would so many newer editors have overtaken it? Why couldn't it keep up?

I do like FP, especially in multi-paradigm languages, but I hate the attitude many academics have that it's clearly superior to OOP and it just because industry programmers are too dumb to get it. Maybe OOP really is just a better fit for a lot of the programming being done outside of academia.

[–]grauenwolf[S] 0 points1 point  (8 children)

And I ask, why, why is subtyping so important?

GUIs. If you are building GUI frameworks then subtyping is incredibly important. But even there, composistion is still king.

[–][deleted] 5 points6 points  (7 children)

I'll respectfully disagree: FRP wins big with GUIs.

[–]grauenwolf[S] 1 point2 points  (2 children)

You are comparing apples with oranges. Subtyping is a way to define the controls in a window. Reactive programming is a way to alter the state of those controls. These techniques are quite compatible.

[–][deleted] 1 point2 points * (1 child)

That's a fair point. Let's put it this way: in traditional GUI frameworks, you inevitably wind up dealing with two hierarchies: a subtyping/subclassing (most OO languages conflate the two) hierarchy expressing static kind-of relations among GUI elements, and a dynamic "containment" hierarchy expressing "handles" relations among events and their handlers. It's true that subtyping nicely captures, e.g. that a menu is a menu is a menu. Two observations:

  1. That doesn't necessarily imply objects (cf. conflating subtyping and subclassing).
  2. FRP addresses the relations between event streams and how they're handled far more effectively than objects.

So I think I'm agreeing with your major thesis while striving to distinguish between subclassing and subtyping on one hand, and kind-of and handles on the other.

[–]grauenwolf[S] 0 points1 point  (0 children)

That doesn't necessarily imply objects

What alternative do you prefer?

My favorite way of designing UI is currently declarative languages, especially XAML. That isn't exactly based on composition or subtyping, as it also heavily uses a form on inheritance closer to CSS than anything else I've encountered. But CSS is just styling, XAML uses it for darn near everything.

[–]jdh30 0 points1 point  (3 children)

Please can you elaborate and give references?

[–]grauenwolf[S] 0 points1 point  (1 child)

FRP or Functional Reactive Programming is just a subset of the broader Reactive Programming model. This has not gone unnoticed by .NET developers.

http://www.infoq.com/news/2009/07/Reactive-Framework-LINQ-Events

[–][deleted] 1 point2 points  (0 children)

That's right--someone else recently pointed me to Rx. Very nice! Thanks!

[–][deleted] 0 points1 point  (0 children)

[–]FlySwat -1 points0 points  (12 children)

I think the point is that when you ask a FP zealot to show you a cool functional program, they will show you factorial, or some other elegant trick.

But then when you ask them to show you a REAL program, you get a blank stare.

[–]sheep1e 15 points16 points  (3 children)

Some real FP programs: CouchDB (Erlang); xmonad, gitit, and darcs (Haskell); and Unison (Ocaml), just to pick from each of a few major FP languages.

[–]notfancy 7 points8 points  (0 children)

You could add MLDonkey as another example of a large-scale OCaml program:

A lot of designers of functional languages have one dream: finding a killer application, outside of the world of symbolic programming ( compilers, theorem provers, DSLs ), that would make their language spread in the open-source community. One year ago, we tackled this problem, and decided to use Objective-Caml to program a network application in the emerging world of peer-to-peer systems. The result of our work, MLdonkey, has superseded our hopes: it is currently the most popular peer-to-peer file-sharing client on the well-known freshmeat.net site, with about 10,000 daily users. Moreover, MLdonkey is the only client able to connect to several peer-to-peer networks, to download and share files. It works as a daemon, running unattended on the computer, and can be controlled remotely using three different kind of interfaces. In this paper, we present the lessons we learnt from its design and implementation.

(Quoted from http://pauillac.inria.fr/~lefessan/papers/#icfp2003)

[–]gtani7 2 points3 points * (1 child)

erlang: rabbitMQ, ejabberd, riak, scalaris

clojure:: incanter, leiningen

Scala: I don't know the landscape so well, but there must be something..

[–]gclaramunt 0 points1 point  (0 children)

Twitter, LinkedIn, FourSquare and many more. It can be argued that they're not coded in a pure functional style, though

[–][deleted]  (1 child)

[deleted]

    [–]JadeNB 4 points5 points * (0 children)

    And the space between is taken by the multi-paradigm languages which are mostly imperative languages in disguise (Python, Ruby, Perl, PHP, etc.).

    I think that there are plenty of multi-paradigm languages, like F# and the various Lisps and MLs, that are mostly functional languages in (possibly very loose) disguise; and plenty more that are neither fundamentally functional nor fundamentally imperative (Mozart, for example, which I think of as emphasising the dataflow programming paradigm).

    EDIT: Sorry, I bracketed that, probably wrongly, as “(mostly imperative) languages in disguise” rather than “mostly (imperative languages in disguise)”.

    [–]jcreed 2 points3 points  (0 children)

    Well, it is talking about programs that can be described in the course of a talk. I'm not sure what you mean by "REAL" programs. The distinction the article is making seems to be between "demos based on mathematical principles" vs. "real-world problems".

    The point I am making is that there do exist useful programs (say, compilers, financial analysis, graphics) that are based on (sometimes rather abstract) mathematical principles. It's more exciting to people who already are biased to like that sort of thing (for example, me) to see how programming languages can embody those mathematical principles.

    Conversely, it's more exciting to people who don't like mathematical abstractions to see demos and examples that aren't so abstract. I'm not saying one audience is better than the other; I'm just saying that the "no factorial please" audience isn't everybody.

    [–]borodino 5 points6 points  (3 children)

    Right. These fp zealots using functional programming are all giving you a blank stare.

    [–]sheep1e 7 points8 points  (2 children)

    The blank stare is because they're wondering how the mathematically-challenged person in front of them got past security.

    [–]username223 2 points3 points  (1 child)

    When was the last time your superior mathematical genius got you through the airport?

    [–]akallio9000 2 points3 points  (0 children)

    Don't fight the stupids. They bring you down to their level and then beat you with experience.

    [–]Felicia_Svilling 1 point2 points  (0 children)

    ..and you just demonstrated jcreed's point.

    [–]JadeNB 12 points13 points  (79 children)

    Use of the terms "catamorphism" or "monad" or "partial application" or "currying" in your introductory talk is an exercise in stroking your own ego ….

    Perhaps it's just a difference in comfort level (since I've used Perl a lot longer than I've used Haskell), but, to me, the concept of ‘currying’ (and, by loose analogy, therefore ‘partial application’) is much more mainstream than that of a catamorphism or a monad; and it's much more likely that a programmer, even one only loosely steeped in the functional yoga, will think “I need currying here” than “I need a catamorphism here” (unless he or she is a Squiggologist).

    EDIT: Then again, I'm a mathematician, not a programmer, so what do I know?

    [–]bitwize 1 point2 points  (1 child)

    ObTwoProblemsJoke:

    A programmer had a problem and thought "I know! I'll use currying!"...

    [–]JadeNB 2 points3 points  (0 children)

    A programmer had a problem and thought "I know! I'll use currying!"...

    … and then, instead of 2 problems, had a problem that output problems?

    [–]smallfishbigpond 0 points1 point  (45 children)

    And there's the problem with languages like Haskell and F# (well, especially Haskell). You can't even understand the frikken "putStrLn" statement without talking about the MOST complicated feature of the language.

    I consider it a design flaw, and went back to CL.

    [–]JadeNB 20 points21 points  (31 children)

    I don't understand this (common) complaint. It seems to me like saying “I don't like to use C, because, just to use a simple string concatenation, I have to understand the assembly code to which it compiles.”

    If you want to understand the theoretical underpinnings of monads, then they're there for you (which is more than many languages built on ad hoc semantics can say); if not, then you say

    Prelude> putStrLn "Hello, world"

    Hello, world

    and Haskell will not give you a quiz about why that happened.

    [–]eurleif 5 points6 points  (27 children)

    It seems to me like saying “I don't like to use C, because, just to use a simple string concatenation, I have to understand the assembly code to which it compiles.”

    I don't think that analogy quite works. The assembly C compiles down to is just an implementation detail; it could just as easily compile down to a completely different form, or be interpreted, or whatever. At least in theory, you can understand C perfectly without knowing anything about assembly. On the other hand, monads are part of the semantics of IO in Haskell. You may be able to blunder around without understanding them, but you'll never truly comprehend Haskell code.

    [–]LowConsuption 19 points20 points  (0 children)

    I think a better point might be : "I don't like to use C, because, just to use a simple string concatenation, I have to understand pointers and memory".

    And you clearly need to understand memory & pointers to make a "good" call to strcat without blowing anything.

    [–]merehap 13 points14 points * (21 children)

    This myth needs to be burned. Tell me what about the following Haskell code screams monads that the C# code does not:

    --HASKELL

    main = do putStrLn "What is your name?" name <- getLine

    putStrLn ("What is your favorite file,  " ++ name ++ "?")
    path <- getLine
    text <- readFile path
    
    putStrLn "The contents of your favorite file are:"
    putStrLn text
    

    //C#

    using System;

    using System.IO;

    public static void Main()

    { Console.WriteLine("What is your name?"); string name = Console.ReadLine();

    Console.WriteLine("What is your favorite file, " + name + "?");
    string path = Console.ReadLine();
    string text = File.ReadAllText(path);
    
    Console.WriteLine("The contents of your favorite file are:");
    Console.WriteLine(text);
    

    }

    It doesn't matter that Haskell uses monads for IO, or that C# uses unnamed feature X for IO. The user is pretty blind to both of these facts.

    Edit: Code formatting

    [–]eurleif 11 points12 points * (20 children)

    Your extremely simple examples look similar, but they're not, and that would become apparent in even slightly more complex code. How would you explain why you need else return () after if statements with no other else clause in IO code without explaining monads? How would you explain why putting a return statement in the middle of an IO function doesn't make it return early, or seemingly have any effect at all? How would you explain the <- operator, and how it can shadow names but not rebind them? Etc.

    Edit: Actually, a simpler and probably more common example: How would you explain why if you want to return the result of an IO function foo, you just put foo args... inside your do statement, but if foo isn't an IO function, you need to use return $ foo args...?

    [–]merehap 2 points3 points  (9 children)

    The way I explain this to newbies is that IO represents a contamination of your program. Therefore values retrieved from or written to IO, need to have an IO wrapper around them. This is just the same as when learning Java that primitive types need to be put in a wrapper object in order to be used in an array. Though Java has changed this since, the concept of wrappers is ubiquitous in programming. Understanding a wrapper is a very separate concept from understanding a monad.

    From my personal experience when first learning Haskell, I didn't learn how monads worked until 3 months later (I only taught myself concepts as they became necessary). I did however know how to write IO, return statements and all, from the first few days.

    Finally, code in IO that is too much more complicated than what I wrote above is many times a code smell in Haskell, which emphasizes keeping logic out of IO. For the project I am currently working on, a clone of the GNU coreutils in Haskell, I've never written any code in IO more complex than what I gave above.

    [–]eurleif 1 point2 points  (8 children)

    If I were a Haskell newbie and someone explained IO to me that way, I would ask, "Ok, so what function do I call to unwrap an IO object?" And of course, the answer is, "You can't, not directly." Once you've explained why not, and what can be done instead, you've pretty much explained monads.

    [–]merehap 5 points6 points  (6 children)

    No, I just say that you can only unwrap IO in a do block. No additional explanation needed, and it has gone over well with those I've taught. This forces people to think about how they use IO, which is a necessary part of learning Haskell, I admit without regret, as it's a good thing. But still, I haven't so much as mentioned the M word to one person I am teaching, and as a result, she's had no problems learning IO.

    I'll acknowledge that most beginner Haskell tutorials out there are foolish for mentioning monads at all. It is a sad state of affairs. This is why "Learn You A Haskell" is the best Haskell tutorial: it doesn't cover monads at all (it might have had some passing references to them, I don't recall).

    [–]eurleif 0 points1 point  (5 children)

    Well, "wrapped value which can only be unwrapped inside of a do block" is semi-close to the definition of a monad in Haskell, isn't it? Obviously, >>= is more fundamental than do blocks, but do blocks can accomplish the same things, and have the same semantics.

    [–]uotcguyeoncieohp 0 points1 point * (0 children)

    That's incorrect. The one-way property of IO values is a special property of the IO monad. Most monads are not like that.

    Edit: Late to this party.

    [–]gmfawcett 8 points9 points  (9 children)

    Those are real cases that a new Haskell programmer will encounter, sure. But are they really that complicated? Sure, it's different from C, but it's not terribly hard to understand if you're willing to try.

    I find the biggest misconception about Haskell is that you have to be a category theorist to use the language reasonably well. I couldn't tell you what the heck a zygomorphism is. But I get monadic IO; immutable let bindings don't freak me out; I'm not afraid of if expressions that require a balancing else; and I'm not terrified that return has an unexpected meaning. It didn't take me long to get that far, and I don't think I'm overly smart, so I suspect many others could get that far too (with a little patience).

    [–]username223 5 points6 points  (3 children)

    I couldn't tell you what the heck a zygomorphism is.

    Sexual intercourse.

    [–]arnedh 0 points1 point  (2 children)

    So what's an anamorphism?

    [–]username223 0 points1 point  (1 child)

    My dictionary says:

    from Greek anamorphōsis ‘transformation,’ from ana- ‘back, again’ + morphosis ‘a shaping’

    so I'm guessing buttseks.

    [–]eurleif 2 points3 points  (4 children)

    Those are real cases that a new Haskell programmer will encounter, sure. But are they really that complicated? Sure, it's different from C, but it's not terribly hard to understand if you're willing to try.

    Right, I agree; it's not very hard to understand how those cases work. However, understanding them implies understanding monads -- maybe not in a crazy mathematical category theory way, but at least in terms of what their basic operations are in Haskell, and how those apply to IO.

    [–]ssylvan 15 points16 points  (2 children)

    There are gazillions more weird and unusual things in a language like C, the difference being that there is no underlying theory to "understand" other than "this is the way it is". The fact that you can understand Haskell's IO in terms of a more principled structure is a good thing, not a bad thing. If you don't want to, you don't have to, you can just accept it as "the way it is", just like you have to for every idiosyncratic part of C.

    [–]shub 1 point2 points  (1 child)

    I'd turn that around and say that C has the advantage. It's (nearly) complete in itself, and if you want to dig deeper it's not hard to see how C maps to the hardware, and that's it, that's the world. From there you can build up to C++ or C# and see how they work.

    Haskell doesn't have that. Understanding Haskell, how it's put together, why it works the way it does, requires learning a theory external to the language; digging into the implementation of putStr is impossible, Haskell has no way to express it.

    [–]gmfawcett 2 points3 points  (0 children)

    Right, I agree; it's not very hard to understand how those cases work. However, understanding them implies understanding monads -- maybe not in a crazy mathematical category theory way, but at least in terms of what their basic operations are in Haskell, and how those apply to IO.

    Certainly, I agree with you there, and there is definitely a greater learning curve to do IO in Haskell than in others languages I've used.

    [–]ssylvan 4 points5 points  (0 children)

    You don't have to understand monads to write IO in Haskell. If you want to write your own monads you obviously do, just like if you would have to write some inline assembly to do various things in C. Eventually you should probably make the effort to understand monads, but to say that you can't understand "putStrLn" to a working level without knowing how it's implemented is simply false.

    [–]naasking 1 point2 points  (2 children)

    Since Haskell has monadic do-notation, I think his analogy to C is spot-on.

    [–]eurleif 3 points4 points  (1 child)

    Do notation is syntactic sugar, not an abstraction, and it doesn't change the semantics of monads.

    [–]naasking 1 point2 points  (0 children)

    It enables you to avoid knowing what's happening in a monad since you don't have to chain lambdas manually. A monadic computation ends up looking like an imperative program, which is eminently understandable to most programmers.

    [–]shub 3 points4 points  (2 children)

    I'm not trying to speak for anyone else, but here's what happened when I tried to learn Haskell:

    1. Oh here is a tutorial. I will learn from it.
    2. Hmm this is interesting.
    3. Okay, the tutorial is interesting but now I am going to do something non-trivial.
    4. HALP WHAT IS GOING ON
    5. Screw Haskell

    I mean 4. literally; I couldn't comprehend Haskell's model of computation. C, Java, Python, Ruby, etc all permit a mechanical model, with the IP and register dump and all that. You can understand code by constructing a CPU in your mind and running code through it. That doesn't work with Haskell.

    Not to mention that it was nearly impossible for me to estimate the time or space complexity of the code I was writing.

    [–]JadeNB 0 points1 point  (1 child)

    Have you tried Real-World Haskell? That was the book that made the difference for me between your step (4) and “Hey, this is a beautiful language!” (Then again, I'm not sure that anything I've done with it counts as non-trivial.)

    [–]shub 0 points1 point  (0 children)

    I have tried it, and put it down around chapter 5. It's a good book, but I won't have time for it until maybe this summer.

    [–]grauenwolf[S] 12 points13 points  (4 children)

    You comment led me to actually look up putStrLn. This is what I read:

    The question immediately arises: "how do you 'run' an action?". This is something that is left up to the compiler. You cannot actually run an action yourself; instead, a program is, itself, a single action that is run when the compiled program is executed. Thus, the compiler requires that the main function have type IO (), which means that it is an IO action that returns nothing. The compiled code then executes this action.

    However, while you are not allowed to run actions yourself, you are allowed to combine actions. There are two ways to go about this. The one we will focus on in this chapter is the do notation, which provides a convenient means of putting actions together, and allows us to get useful things done in Haskell without having to understand what really happens. Lurking behind the do notation is the more explicit approach using the (>>=) operator, but we will not be ready to cover this until the chapter Understanding monads.

    http://en.wikibooks.org/wiki/Haskell/Simple_input_and_output

    Now translated into C:

    The question immediately arises: "how do you 'run' a statement?". This is something that is left up to the compiler. You cannot actually run a statement yourself; instead, a program is, itself, a single statement that is run when the compiled program is executed. Thus, the compiler requires that the main function have type void, which means that it is a statement that returns nothing. The compiled code then executes this action.

    However, while you are not allowed to run statements yourself, you are allowed to combine statements. There are two ways to go about this. The one we will focus on in this chapter is the semi-colon notation, which provides a convenient means of putting statements together, and allows us to get useful things done in C without having to understand what really happens. Lurking behind the * semi-colon* notation is assembly, but we will not be ready to cover this until the chapter Understanding calling conventions.

    See? All you have to do is translate their mumbo-jumbo into the mumbo-jumbo we are already familiar with and it becomes quite approachable.

    [–]Minimiscience 9 points10 points  (2 children)

    Now translated into C: ... Thus, the compiler requires that the main function have type void

    AAHHH!!!!! ANATHEMA!!! main() does not return void; main returns an int! Failure to return a value from a non-void function leads to undefined behavior! Support for prototypes of main other than int main(void) and int main(int, char**) is implementation-defined! You can't go outside the Holy ISO Standard, or else demons will fly out of your nose! You can't do that... it's non-portable... it's not guaranteed to work... \curls up into a fetal position in the corner and sobs**

    [–]grauenwolf[S] 4 points5 points  (1 child)

    Um, I'm sorry.

    [–]JadeNB 0 points1 point  (0 children)

    Did you say mattress to Mr Lambert?

    [–]shub 3 points4 points  (0 children)

    That is not a valid transformation.

    [–][deleted]  (6 children)

    [deleted]

      [–]JadeNB 0 points1 point  (0 children)

      How exactly does one determine that going back to CL is the "easiest" thing to do?

      There was no implication that it was the easiest thing to do (except possibly for smallfishbigpond him- or herself):

      And there's the problem with languages like Haskell and F# (well, especially Haskell). You can't even understand the frikken "putStrLn" statement without talking about the MOST complicated feature of the language.

      I consider it a design flaw, and went back to CL.

      EDIT: Fixed the missing link.

      [–]-main 0 points1 point  (0 children)

      You actually don't have to deal with pathnames. An "x designator", in the terms of the hyperspec, is "any one of several different types that could be understood as an x". So you just use truename namestrings and it works, no need to use pathnames or logical pathname translations or anything. You don't even need to know what they are. I'm a common lisp coder, and I never use logical pathnames.

      [–]G_Morgan 0 points1 point  (3 children)

      I abandoned it because on dominant implementation is not forthcoming and they cannot even get whether a drive letter is a device or a partition consistent on Windows.

      [–][deleted] 0 points1 point  (2 children)

      Why would there be a dominant implementation, any more than there's a dominant implementation of C++ or Fortran?

      [–]G_Morgan 1 point2 points  (1 child)

      C++ doesn't need a dominant implementation because its standard isn't riddled with compromise, vagueness and strong recommendations. CL only needs a dominant implementation because key parts of the standard library have been made so generic that everybody implements them differently. As I said one major CL implementation sees a drive letter as a device and another sees it as a partition. Portable code is impossible. In C++ I do not have this problem between implementations.

      Multiple implementations are practical if your standard is sane. While CL has a standard it is a crappy one. The various non-standardised Pythons are closer in behaviour than CL implementations (that all meet the standard) are.

      [–][deleted] 0 points1 point  (0 children)

      On the one hand, you're pretty much right about pathnames. They're too underspecified to be particularly useful. You're almost always better off just using namestrings and letting the implementation figure out whether "C:" is a drive or a partition.

      On the other hand, the rest of the standard is much more precise. I can't think of one other language feature that's close to as problematic as the pathname stuff.

      [–]olavk 1 point2 points  (0 children)

      I consider it a design flaw

      It would be a design flaw if Haskell (like eg. Python) was designed with the explicit intention of being easy to approach even for beginners. But Haskell is clearly designed with the expectation that the user will make the upfront investment in learning how to use it.

      I do agree that it is a major obstacle in learning Haskell that you have to understand the IO monad to be able to write "Hello world". However the Haskell motto is "Avoid success at all costs", so I'm not sure this is considered a design problem.

      [–]HugeIsALegoManiac 2 points3 points  (5 children)

      Wow.

      From what the OP said NOT to do, it sounds like F# might actually be interesting and not just for math nerds which the presentation he sat through reinforced.

      Does anyone have any links or material on F# that do the things he suggests? (e.g. doesn't use boring examples, shows how it's actual useful)

      [–]Devilboy666 1 point2 points  (0 children)

      Watch this video - it's super entertaining and shows how you can use F# in a 'normal' development task

      http://channel9.msdn.com/pdc2008/TL11/

      [–][deleted] -2 points-1 points  (1 child)

      F# is meant to be used for mathematical style programs. If you want to write database front ends then that's what C# is for.

      [–]Devilboy666 -3 points-2 points  (0 children)

      You must be a woman. Because you're totally wrong.

      [–]Peaker 2 points3 points  (0 children)

      When explaining functional programming, I like to explain using the approach in "Why Functional Programming Matters".

      Basically, it compares the replacement of "goto" with structured code (loops, conditions, later exceptions), with the replacement of mutable variable writes/reads and argument/return value passing.

      goto's basically let you manipulate the control flow freely, but this means that understanding what happens in your program is difficult and correctness is difficult.

      mutable variables, similarly, let you manipulate data flow (between mutable cells) freely, but this means that understanding what happens is difficult and correctness is difficult. Whenever you have one entity writing into a mutable cell, and another entity reading from it -- you could instead restructure the code to have the entities pass an argument or return value to one another.

      This kind of restructuring, similarly to the restructuring that needs to be done to replace goto's with structured code, is not systematic and trivial. It takes careful analysis about what the code is trying to achieve with those lower-level primitives, and then encoding those with the higher-level ones (structured loops or arguments/return values).

      Just like structured code reveals the structure of your control flow, functional programming reveals the structure of your data flow. It becomes clear what is defined in terms of what and how.

      Additionally, when your code uses argument/return value passing rather than mutable cells -- the type system can help catch much more bugs. If you forget to write to a mutable cell, the type system will not catch that. If you forget to pass an argument or return a result, however, it will.

      [–]Leonidas_from_XIV 5 points6 points  (13 children)

      DON'T stress the F# Interactive environment

      Heh, no REPL means dealbreaker to me in almost all cases.

      [–]G_Morgan 2 points3 points  (8 children)

      You aren't the target though.

      [–]Leonidas_from_XIV 0 points1 point  (7 children)

      Then who is?

      [–]G_Morgan 5 points6 points  (6 children)

      The Java and C# only guys who form the 'mainstream'. Anybody who demands a REPL is already in the group who would be prepared to accept new ideas. Frankly a REPL suggests Lisp, Ruby, Python or Perl. Other than the last I'd say those types of programmers are more likely to be open to functional programming.

      I've always said this about functional. You should make it look as close to programming in C# as possible. Not necessarily the language but the use of tools and the programming work flow. What people react against is change and the REPL is in fact a draw back when trying to attract people from edit, compile, run cycle development. The number of alien aspects need to be minimised. People will pick up REPLs later on.

      [–]JadeNB 0 points1 point  (0 children)

      Frankly a REPL suggests Lisp, Ruby, Python or Perl.

      Aside from the general scripting-language feel, Perl doesn't belong on that list unless you count Devel::REPL.

      [–]igouy 0 points1 point  (4 children)

      [–]G_Morgan 2 points3 points  (3 children)

      The existence of a C# REPL doesn't really suggest anything. How many C# programmers use it day to day? The issue is not what is possible. It is what is expected. Maybe convincing C# programmers to start with a REPL and then introducing F# is a better approach.

      [–]igouy 1 point2 points  (2 children)

      How many C# programmers use it day to day?

      Do you know? You seem to be saying that it isn't used day to day.

      [–]G_Morgan 1 point2 points  (1 child)

      In my experience it isn't used. All the C# programmers I've seen use VS and a traditional edit, compile, run cycle.

      [–]igouy 0 points1 point  (0 children)

      Things change - new crops of programmers gain their first programming experiences without edit/compile/run.

      [–]runT1ME 0 points1 point  (3 children)

      Because REPL is the secret to productivity?

      [–]Leonidas_from_XIV 2 points3 points  (2 children)

      I wouldn't go that far (poductivity is a the sum of many things), but it is incredibly handy to try things out and learn new stuff without needing to go through the edit-compile-link-cycle again. I would say it encourages experimentation and that is quite important to me.

      [–]mareek -1 points0 points  (1 child)

      I've got a "sandbox" C# project that compiles in less than a second (as it's almost empty) so I don't find REPL usefull for this kind of tasks.

      [–]Leonidas_from_XIV 0 points1 point  (0 children)

      It is not the length of compiling, it is the instant (no manual compile step at all) feedback that encourages exploratory programming. I know that compilers can be very fast so that a compile-run-cycle is not long but I have found out that the REPL changed my way of working so much that everything else feels kludgy.

      [–]noiserr 4 points5 points  (33 children)

      DON'T answer the inevitable "why should I care?" question with the word "productivity".

      I hate to be the one to point this out, but every language ever introduced has held this up as a reason to switch to it, and none of them have ever really felt like they were a productivity boost, at least not in the long run. And if you answer with, "Because I just think that way", that's a FAIL on your part, because I can't see how your thinking changes mine. (You may also like the Pittsburgh Steelers, while I know they can't hold a candle to the New Orleans Saints—now where are we?)

      Really? There is no productivity gain in rapid development between following languages: C++, Java, Python ?

      [–][deleted] 2 points3 points  (1 child)

      Really? There is no productivity gain in rapid development between following languages: C++, Java, Python ?

      Yes, that's exactly the problem: whenever the words "increased productivity" are said, half of the audience imagines something along the lines of Java to Python, that the language allows you to be very productive at writing 20 line throwaway scripts. Another half interprets your words to mean that the language boosts productivity of mediocre coders who don't know about smart pointers and are afraid of templates.

      [–]noiserr 1 point2 points  (0 children)

      On the same token, features like list comprehensions, lambdas, terse syntax, specialized frameworks (Ruby, Django) make for a incredibly fast turnaround.

      [–]grauenwolf[S] 4 points5 points  (28 children)

      I can certainly attest to the jump from C++ to Java. As for Python, the .NET langauges stole enough to make that meaningless for me.

      [–]julesjacobs 2 points3 points  (24 children)

      .NET languages are in the middle between Java and Python for me. Python is a lot simpler and terser. In C# it feels like you have to jump through hoops to encode your problem whereas in Python it's more like expressing your problem as opposed to encoding it.

      Have you tried (Iron)Python seriously? I'm sure you'd love it.

      [–]thomasz 2 points3 points  (21 children)

      Python is a lot simpler and terser.

      This gap has nearly been closed for me by c# 3.5 with Linq, static extension methods, local type inference and anonymous types.

      [–]julesjacobs 0 points1 point  (20 children)

      Yep, it's better than it used to be. Lexical scoping is a big thing I miss in C#. And I dislike the boilerplate you have to write. Part of it is the language, e.g. you have to write out types, create a class when all you need is a function, decorators, indentation based syntax:

      if(x){ // C# programmers usually put every { and } on it's own line
         ...
      }else{
         ...
      }
      

      vs

      if x:
         ...
      else:
         ...
      

      The other part is verbosity in the libraries. Compare working with sets in C# vs working with sets in Python. I doubt the gap can ever be fully closed without big changes to C#.

      [–][deleted] 0 points1 point  (5 children)

      Lexical scoping is a big thing I miss in C#

      You mean in Python?

      btw, what I really miss in Python is let clause in generator expressions.

      [–]julesjacobs 0 points1 point * (4 children)

      No, no, in C#. Python has better lexical scoping, unfortunately it's not perfect either, especially if you mutate variables. I miss the full power of Linq in Python too, but for the common case Python's list comprehensions are slightly more concise.

      [–][deleted] 0 points1 point  (3 children)

      What? Python has abysmal lexical scoping: only function and class definitions create scopes, so variables from different blocks are spilled all around, captured by lambdas/nested functions unpredictably etc. And yes, implicit declaration makes it painful to modify anything in the outer scope. On the other hand, what exactly don't you like in C# scoping?

      for the common case Python's list comprehensions are more concise.

      If by concise you mean that for and if are shorter than from and where, and select is unnecessary, then yes, but I don't think that's important. If you mean that return value goes in front, then I strongly disagree, I prefer my variables being declared strictly before use (lexically), so OCaml, Haskell and others can shove their stupid mathematical idiosyncrasies where sun doesn't shine. And there are no more differences between LINQ and Python generators.

      [–]julesjacobs 1 point2 points  (2 children)

      On the other hand, what exactly don't you like in C# scoping?

      Nested methods/functions look ugly. Global scoped things have to be in classes, e.g. global variables have to be in a class. There are multiple scopes: one for classes and one for values. In Python classes are values, so there's only one type of scope. This isn't a big difference but the way Python works just fits my mind better. I come up with a solution and in Python I can write it down but in C# I have to pay more attention to how I encode it and worry about how to get data in the right place of the program.

      I prefer my variables being declared strictly before use (lexically)

      I strongly agree. When writing a list comprehension in Python I always start writing the code backwards.

      [for x in xs]
      [f(x) for x in xs]
      

      This would be my ideal:

      [x in xs: f(x)]
      

      or maybe

      [for x in xs: f(x)]
      

      If by concise you mean that for and if are shorter than from and where, and select is unnecessary, then yes, but I don't think that's important.

      Agreed.

      [–][deleted] 0 points1 point * (1 child)

      Nested methods/functions look ugly. Global scoped things have to be in classes, e.g. global variables have to be in a class.

      Agreed.

      There are multiple scopes: one for classes and one for values.

      Explain this with examples, please.

      In Python classes are values, so there's only one type of scope.

      No! Absolutely not, and this bothers me immensely! When you have nested functions, you can read any variable from the outer scope without any problems, because with functions you have true lexical scope -- all variable names are known at compile time (i.e. when source is compiled into bytecode). With classes it's different: after the class definition was executed, everything that was defined in its scope is collected in the class' dictionary and is not accessible by other means. A case in point: since class scope isn't lexical scope you can't access class members from a @staticmethod with unqualified name and have to use a fully qualified name, like MyClass.something. This sucks!

      In fact Python has a fairly generous lot of gnarly suckage like this, I'd even go as far as to say that its object model is the most contrived of any language I've used, even more complex and scary than C++'s, unless you wander into template territory there. Yes, most programmers most of the time don't have to deal with this complexity, but as soon as you want to implement something nontrivial (which usually is a bad idea, but still) the maw of chaos is agape and waiting.

      EDIT: I've remembered the case when Python class scope demonstrated its retardiation for me: I tried to make a decorator which collects decorated methods in a special field. So that I would be able to write

      parsers = {}
      
      @classmethod # or staticmethod, doesn't matter
      def parser(cls, s):
           def wrapper(f):
                 # here I'm trying to put f into parsers
      
      @parser('blah blah')
      def parse_something(self):
           pass
      

      and then have a nice collection of all parsers. BAM! I can't refer to parsers directly because it's not a lexical scope, AND I can't use the fully qualified name either, because when the decorator runs the class is not defined yet! Catch 22!

      [–]munificent 0 points1 point  (4 children)

      write out types

      Do you mean in declarations? You can use var for local variables, which are the majority of type declarations.

      create a class when all you need is a function

      Why would you need to do this? C# already has closures, delegates and even built-in generic delegates so that you don't have to declare your own delegate types.

      decorators

      Attributes give you some of what decorators or nice for but, yes, a dynamic language wins here.

      indentation based syntax:

      Yeah, I hate curlies and semicolons too. :(

      [–]julesjacobs 3 points4 points * (1 child)

      Do you mean in declarations?

      Yes, in member variable declarations and method arguments and type parameters.

      Why would you need to do this? C# already has closures, delegates and even built-in generic delegates so that you don't have to declare your own delegate types.

      public static class FooUtils
      { 
          public static BarType Foo(BazType x)
          {
             ...
          }
      }
      
      def foo(x):
         ...
      

      Oh and another problem is that types sometimes get in the way. Then you can either ditch type safety and go dynamic or work around it by cut-and-paste programming. The most common scenario is a generic class/interface Foo<T> that has methods bar and baz, but if T supports some interface I then Foo<T> should support a method foo and Foo<T> should support interface I.

      [–]munificent 2 points3 points  (0 children)

      Yes, in member variable declarations and method arguments

      Those do suck, especially member variables. Method parameters both me less because I like the safety of static types but don't want the slow compile times of a Hindley-Milner language. I also, personally, like seeing type annotations for a method because it's useful documentation to me.

      type parameters.

      Type inference covers some of this space. The only time you need to specify a type parameter is when there's no other way the compiler could infer it.

      public static class FooUtils

      Ah, now I understand. I'd like non-class functions too. Extension methods go part of the way. In practice, it's not too much of a problem for me. Only a very small fraction of my code has functions where there isn't already a logical class to put them into.

      The most common scenario is a generic class/interface Foo<T> that has methods bar and baz, but if T supports some interface I then Foo<T> should support a method foo and Foo<T> should support interface I.

      That doesn't line up with how I reason about generic types. Can you give a more concrete example here? I don't think I've ever run into the situation you describe.

      [–]grauenwolf[S] 0 points1 point  (1 child)

      create a class when all you need is a function Why would you need to do this?

      It is rather annoying to always have to prefix your library functions with namespaces in C#. For example:

      C#: a = HttpUtility.HtmlEncode(b);
      VB: a = HtmlEncode(b)
      

      [–]munificent 0 points1 point  (0 children)

      My solution these days for that is to make it an extension method.

      public static class StringExtensions
      {
          public static string HtmlEncode(this string source)
          {
              return HttpUtility.HtmlEncode(source);
          }
      }
      
      a = b.HtmlEncode();
      

      [–]grauenwolf[S] 0 points1 point  (5 children)

      Well then there is VB. If you don't use strict typing, the only time you have to declare types is when implementing an interface or event handler.

      [–]julesjacobs 0 points1 point  (4 children)

      Sure that's a plus, but one can hardly claim that VB is as clean as Python.

      [–]grauenwolf[S] 1 point2 points  (3 children)

      Hard to say, they both have warts, some of which are serious. But at least both of them need a lot less boiler plate code than C#. It is hard to believe they still have the same broken if, for, and switch statements that C had decades ago.

      [–]julesjacobs 1 point2 points  (2 children)

      What do you mean by broken if, for and switch statements? Do you mean in C#? Broken for and switch I understand in that case, but what's wrong with if?

      [–]grauenwolf[S] 0 points1 point  (1 child)

      Common bug #1: Accidentally assigning instead of comparing

      if (x = 0 ) 
          { DoSomething(); } //this never happens
      

      Common bug #2: Accidentaly semi-colon on the if-block

      if (x == 0 );
          { DoSomething(); } //this always happens
      

      Common bug #3: Accidentaly semi-colon on the else-block

      if (x == 0 )
          { DoSomething(); }
      else;
          { DoSomethingElse(); } //this always happens
      

      Common bug #4: Dangling else block caused by commenting out a line

      if (x == 0 );
          { DoSomething(); }
      else 
          //{ DoSomethingElse(); }
      
      AlwaysDoThis(); // this may or may not happen
      

      Common bug #5: Forgotten braces

      if (x == 0 ) 
           DoSomething();  
           DoSomethingElse();  //this always happens
      

      [–]grauenwolf[S] 0 points1 point  (2 children)

      Compare working with sets in C# vs working with sets in Python.

      Example please.

      [–]julesjacobs 1 point2 points  (1 child)

      In math:

      win(b) = exists n in b such that not win(b \ {n-1,n,n+1})
      

      In Python:

      def win(b): return any(not win(b-set([n-1,n,n+1])) for n in b)
      

      Translate that into C#. It will look similar but not as nice.

      Python: s1 - s2
      C#: var temp = s1.Copy(); temp.ExceptWith(s2); temp
      

      In Python sets are something you'd use all the time without making a big deal about it. In C# sets are syntactically heavy.

      [–]grauenwolf[S] 1 point2 points  (0 children)

      It is a pity that we can't use extension methods to add the missing operator overloads on C# classes.

      [–]grauenwolf[S] 1 point2 points  (0 children)

      Have you tried (Iron)Python seriously?

      Yes and no. I am currently using IronPython as a scripting language in XAML. I see it as an alternative to writing value converters in VB or C#, but not as a primary language.

      EDIT: Just to be clear, I strongly dislike dynamically typed langauges. However, since XAML data binding is already dynamically typed so given that context why not use the best available?

      [–][deleted] 2 points3 points * (2 children)

      Dear .NET Programmer,

      Yo dawg, I heard you like machines. So I built you a machine to run on your machine so you could have a program to run your programs.

      Sincerely yours, C++ Programmer.

      [–]grauenwolf[S] 1 point2 points  (1 child)

      Dear C++ programmer.

      I'm sorry but things aren't working out. Sure we had some laughs and we like the garbage collector you gave us. But the compilers, man those are really holding us back. We need to grow and that means rewriting them all in our own languages.

      Sincerly yours, .NET Programmer.

      P.S. We are taking Windows Phone in the divorce. You did enough damage to its older siblings.

      [–]shub -1 points0 points  (1 child)

      Depends. Sometimes the solution to a problem is most clearly expressed by some pointer arithmetic and bit-banging...good times.

      [–]noiserr 0 points1 point  (0 children)

      Agreed, right tool for the right job withstanding in general though there is a big difference.

      [–]heavy-minium 1 point2 points  (0 children)

      lol, next to his website I looked at the ".NET Developer Association meeting" blog. and it seems every meeting incorporates free pizza at 6:45 pm :D Stereotype bling bling

      [–]Whisper 0 points1 point  (0 children)

      I hate to tell you this, but most of the developer community is not convinced that functional programming is "obviously" the right way to program. Attempting to take them deep into functional mojo is only going to lose them and overwhelm them and quite likely convince them that functional programming is for math majors. Use of the terms "catamorphism" or "monad" or "partial application" or "currying" in your introductory talk is an exercise in stroking your own ego, not in teaching the audience something useful.

      Reddit, are you listening?

      [–]xTRUMANx 0 points1 point  (0 children)

      Anyone got links explaining in a manner described by this post? In written form as well, videos won't do for me.

      [–][deleted] 0 points1 point  (0 children)

      The Brisbane Functional Programming Group recently had a speaker on F#.

      [–]Otis_Inf 0 points1 point  (0 children)

      Ted Neward... the guy who called 'O/R mapping' the vietnam of software development, in public. And we should take advice from him about speaking?

      [–][deleted] -1 points0 points  (0 children)

      DO stress that F# can do everything C# or Visual Basic can do.

      Although you can hook into all the .NET libraries and system calls the language is not suited for that.

      The intended use of F# is for writing of libraries for financial or scientific computing.

      Those libraries can be used in C# or VB or IronRuby or IronPython or whateverhaveyou for other bits and pieces that those languages are suited for.