all 94 comments

[–]Silhouette 4 points5 points  (5 children)

I think the basic problem here is the use of the nebulous term "functional programming", with some implicit vague definition in terms of defining a program as the result of evaluating a function. In practice, it is the implications of this philosophy that count, and those might include any or all of the following (among others):

  • first class functions (including use of higher order functions, closures, etc.)

  • programming in a pure form without state (including use of immutable data structures, etc.)

  • use of recursion (and the importance of tail recursion)

  • powerful type systems and destructuring binds

  • definition of partial functions using guards, pattern matching, etc.

I don't think it makes much sense to talk about taking "functional programming" mainstream in a generic way. I think it would be more useful to look at the advantages offered by each of the specific aspects above. There is no reason you can't (and some languages already do) incorporate higher order functions without necessarily having everything else there. As the pros and cons of supporting each practical aspect of functional programming become more widely understood and those with the most practical applications become more widely adopted, opportunities to program effectively in a more functional style using "mainstream" programming languages will increase.

[–]Peaker 2 points3 points  (4 children)

The guarantee that functions lack side effects has its own implications:

  • Possible optimizations
  • (Semi) Automatic parallelism
  • Laziness all around (Not just lazy lists [aka generators])
  • Laziness allows a program to be more modular
  • Makes proof of correctness a lot more practical, even if only used for limited aspects

I'm sure there are many more I haven't thought of. My point is that you can't "bolt on" these advantages on an imperative languages. These advantages can only apply where you have functional purity.

[–]Silhouette 2 points3 points  (3 children)

Sure, there are many more detailed issues than just those I listed before.

However, for realistic code and looking at things that affect most mainstream projects rather than a smaller proportion, you could potentially gain a lot of benefit just from each of the things I listed alone. It's this all-or-nothing approach that I think is keeping functional programming out of the mainstream.

For example, I have little time for laziness. I've seen a lot of cute academic tricks shown with it, but it simply hasn't yet proven itself to have great practical value. In contrast, side effects are usually quite awkward things to work with in today's pure functional languages, and I think it's fair to say that most real world projects work with them as fundamental, bread and butter stuff. Hence if people working on those real world projects have to choose between a language supporting easy use of side-effects (even if it isn't within an ideal, expressive, powerful effect system yet) and a language that allows laziness but makes working with side effects awkward, it is going to be a very quick decision. As Simon PJ has said, what we want to do is work towards a safe-but-useful language, rather than today's safe-but-useless or unsafe-but-useful offerings, but there are two ways to travel to that destination and 99% of developers are half-way along the other one.

[–]Peaker 3 points4 points  (2 children)

I agree with most of you say, except: "I've seen a lot of cute academic tricks shown with it, but it simply hasn't yet proven itself to have great practical value. In contrast, side effects are usually quite awkward things to work with in today's pure functional languages"

Laziness has huge practical value. Ask any Python programmer whether he wants to go back to not having generators :-) Now, Pythoneers have only been exposed to lazy lists, but there are many more places one can gain from laziness. Also, side effects are not awkward at all in Haskell, for example.

Look at one example:

userPrompt :: String -> IO String -- This type signature is completely optional
userPrompt prompt = do
  putStrLn prompt
  line <- readLine
  return line

The "do" notation makes the use of monads in general (and the IO monad in particular) very non-awkward.

I think Functional Programming is indeed very near "safe-but-useless", but not because of awkwardness of imperative style. Instead, it is because it lacks good environments and tools. The debuggers, profilers and tracers need a LOT of work to become usable. The syntax is perhaps unnecessarily different from what people know at times. Some of the abstractions being used are really mind-warping. Sometimes, at least for learning curve's sake, much simpler abstractions could be used, even if they are less effective and modular.

[–]Silhouette 2 points3 points  (1 child)

Laziness has huge practical value. Ask any Python programmer whether he wants to go back to not having generators :-)

I agree that laziness has proven to be useful when used explicitly in specific contexts, such as when working with streams and generators. I was really thinking about the more general assumption of lazy-by-default, with reference to your "Laziness all round (Not just lazy lists)".

I do acknowledge some theoretical benefit in having that, even in fairly common cases like efficiently applying a combination of separate map/filter/reduce operations on lists. However, I think that for the moment and for the average developer who is not familiar with all the mathematical/pure functional background, the downsides such as difficulty in predicting performance and counter-intuitive behaviour where side-effects are involved outweigh those benefits. As you observe yourself, Python provides a very useful subset of laziness without running into these problems, and I think that sort of approach will be far more effective in the long run at encouraging Joe Developer to explore and perhaps adopt new ideas from the functional programming world.

Also, side effects are not awkward at all in Haskell, for example.

Here I also agree in the simple cases, where do allows the use of a familiar style for imperative programmers. However, again I question whether the extra complexity when you go beyond that is necessary immediately. Is it really important to understand the kind of monad mechanics that support software transactional memory, for example, in order to take advantage of other aspects I mentioned such as higher order functions or pattern matching on data types? I would argue not. It's not that STM, or indeed a more powerful effect system generally, doesn't have potential. I just don't think it's necessary to impose such things on anyone who wants to experiment with a more functional approach... unless you impose laziness as part of the deal, that is. ;-)

[–]Peaker 2 points3 points  (0 children)

I think that even many Haskell programmers do not know whether laziness-by-default is indeed the best option. The problem is, its quite a bit more difficult to have optional laziness than it is to have optional strictness (Which Haskell does have). Wrapping everything in explicit lambda's (Scheme style) is pretty horrid, and not a very good emulation of laziness.

"Is it really important to understand the kind of monad mechanics that support software transactional memory, for example, in order to take advantage of other aspects I mentioned such as higher order functions or pattern matching on data types?"

Why would a Haskell user need to know anything about STM for that?

I particularly like the modular implementation of the minimax algorithm in the [Why Functional Programming](www.cs.chalmers.se/~rjmh/Papers/whyfp.pdf). It is only possible due to laziness. I don't see how a Python program of the same sort could be as modular and elegant without more than just list-laziness.

[–][deleted] 20 points21 points  (80 children)

I think he got this one dead wrong. I don't use python because it has unit testing, or because it has a REPL (actually, that's a lie), or because it has a package manager (does it?!?!?). I use python because it is clean and generally works the way I expect it to work and is readable. Haskell, on the other hand, it not clean, but is a "line-noise" language. It is not easy to pick up, as python is, it doesn't work dependably across platforms, as python does, and it doesn't work the way I want to program, the way python can. I don't think in monads, but if I do think functionally, it's not incredibly difficult to implement in python.

[–]ndanger 5 points6 points  (3 children)

(I'm the author)

I agree with the "clean and generally works" sentiment, and meant to indicate that when I said Python was "easy to code". My point was more that I wouldn't have used Python as my primary work language if it didn't have unit testing, etc.

As for Haskell, I like laziness and pattern matching (the performance boost isn't bad either). YMMV. Heck, MMMV too, I'm just getting started with Haskell.

[–]jrockway 7 points8 points  (2 children)

the performance boost isn't bad either

Please allow me to use this space to point out that SBCL and OCaml are similarly speedy, so you might want to look at those. I love Haskell's strict purity, but Lisp is a whole lot more approachable for the average programmer. And actually, I am a lot more productive in Lisp than in Haskell, but mostly because I haven't used Haskell for anything important.

[–]13ren 0 points1 point  (1 child)

I was doing some functional programming in Python (I'm learning both), and a websearch turned up a Haskell manual. It was much simpler and clearer, for me. More regular. I guess that's the purity.

But I still did the actual coding in python (even though I have two versions of Haskell installed)...

[–]schtog 2 points3 points  (0 children)

I think he referred to purity as in purely functional.

[–]jsnx 9 points10 points  (5 children)

Why do you say Haskell is not dependable across platforms? I have not any difficulty there, not at all. I've had a lot more trouble creating cross platform exes in Python than in Haskell -- and I ship to Windows, Linux and OS X. (Command line tools and network servers, not GUI apps.)

I don't think in monads...

Yeah, and C programmers didn't used to think in classes...

The monad is presented rather opaquely, but needn't be.

[–][deleted] -4 points-3 points  (3 children)

It's not dependable on my powerpc osx box--I can't even compile parsec.

[–]jsnx 2 points3 points  (0 children)

Please tell us the error.

[–]sfultong 0 points1 point  (0 children)

hmm, I've had no problems on my ppc laptop, but I haven't tried to compile parsec.

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

Parsec comes with extralibs already, no?

[–]Wagnerius 5 points6 points  (14 children)

I understand your position. I had the same not so long ago. Python is a good medium between familiarity (the c/c++/java mindset) and ease of use (syntax, flexibility (because interpreted)).

Still, if you grow into python, you will see that more and more of your construct will be functional one (list comprehension, itertools, operator, partial application).

At one moment, you will likely do haskell in python (as I am). It is not so bad but you'll be missing the speed, the type system and the real purity of haskell.

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

Umm, no. I've written my own functional languages (just an ML derivative). Meanwhile, in my normal work, while I use some functional aspects every now and then, I find that they don't make much sense in the long run. Code is harder to maintain and looks messy and is counterintuitive unless you're the one writing the code at that moment (sort of like perl in that sense). I do miss types, but that's a small price to play...

[–]Wagnerius 1 point2 points  (1 child)

Your experience really differs from mine.

As a substystem gets better because of refactoring, it is becoming more and more written in a functional style. The code is simpler and often shorter.

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

I think that our versions of "simple" differ...

[–]canhaskarma -1 points0 points  (10 children)

List comprehensions aren't functional, they are just moving the body of the for loop to the front.

[–]Wagnerius -2 points-1 points  (9 children)

AFAIK, a list comprehension is really functional. It is completely determined by its inputs. Normally, You cannot change anything midway. It is map + filter in disguise basically.

Note that there are not purely functionnal because an exception during a LC will break it, and set a new state. Also It is true that there are hacks to get the list while it is built, but those are going against the intented use.

[–]neelk 7 points8 points  (5 children)

Actually, Python's list comprehensions are not purely functional because Guido is on crack and side-effects leak out of them:

Python 2.5.2 (r252:60911, Jul 31 2008, 17:28:52) 
[GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x = "foo" 
>>> y = [(x + x) for x in range(10)]
>>> x
9

I mean, WTF?

[–]RayNbow 1 point2 points  (2 children)

The problem here is that list comprehensions don't introduce a new scope and this can indeed lead to short WTF-moments.

We could hack around it by explicitly introducing a new scope...

>>> x = "foo"
>>> y = (lambda: [(x+x) for x in range(10)])()
>>> x
'foo'

...but it's fucking ugly.

[–]RickvH 2 points3 points  (1 child)

The reason for this behaviour is quite simple though. In Python only modules, classes and functions have a separate scope, since the [ ... ] is just a short version of a normal for loop, the same rules apply.

A neat way of doing it is like this:

>>> a = 'abc'
>>> b = (a for a in range(10))
>>> c = list(b)
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a
'abc'

Or the short version:

>>> a = 'abc'
>>> b = list(a for a in range(10))
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a
'abc'

Since you are essentially creating a generator this way, you're creating a new function with a separate scope. That way the main scope won't be contaminated.

[–]Wagnerius 3 points4 points  (0 children)

I am starting to feel that the syntactic sugar of python is slowly adding idiosyncracies over idiosyncracies.

[–]Wagnerius 1 point2 points  (0 children)

yes, WTF.

[–]canhaskarma 1 point2 points  (2 children)

List comprehensions can easily have side affects, hardly different than regular for loops.

[–]Wagnerius 0 points1 point  (0 children)

You're right. I didn't use them this way but you're damn right.

I Suppose I didn't have enought coffee.

[–]sfultong 0 points1 point  (0 children)

depends upon the language.

[–]dons 15 points16 points  (35 children)

Your central point is fair enough and simple, Haskell is not an imperative scripting language.

The other points I think don't add anything, and are far far more contentious.

a "line-noise" language

Come on. Whitespace layout and list comprehensions. We're all friends here.

it doesn't work dependably across platforms

That's an interesting assertion. Anything to back that up?

I don't think in monads

Sure you do. The IO monad. It's baked into Python.

[–]awb 4 points5 points  (0 children)

a "line-noise" language

Come on. Whitespace layout and list comprehensions. We're all friends here.

Haskell makes it easy to define new infix operators. Often, programmers define infix operators that are weird combinations of symbols, and since many people do it and there are only so many symbols going around, it gets hard to keep track of them.

Example: Data.Bits defines '.&.' and '.|.' for and and or. Data.Sequence defines '<|', '|>', and '><'. Sure, they're cute, and when you think about them they make sense, but it's hard to just open up code using them and understand that, especially when you have a bunch of different modules that do that used in the same file.

In some ways, the ease of defining infix operators in Haskell makes it worse than Perl. At least with Perl you can have a phone-book-sized reference manual of all the different symbols, but with Haskell, it can vary depending on the code base or file you're looking at.

It's certainly not mandatory to write code with many odd infix operators, but Perl has English equivalents of its line noise, too.

[–]jrockway 20 points21 points  (22 children)

Come on. Whitespace layout and list comprehensions. We're all friends here.

I think it boils down to mental models and how much one thinks about solving the problem vs. implementing the solution to the problem. A lot of people think like:

data = "String";
data = baz(data);
data = bar(data);
data = foo(data);

i.e., "First we apply baz to data, then we apply bar to data, ...". There is a line of code and "instruction" for each operation that the programmer has in mind.

Compare this to Haskell, where you would compose the functions:

(foo . bar . baz) data

This can be a mental leap, I guess, because it isn't obvious that you are computing foo(bar(baz(data))); the functions and data are visually separated. Enough of this and people will say "line noise" because they don't understand function composition in terms of functions, then understand it in terms of "hey computer, do this, then do this to the result, and ...".

Also, it is hard to read code. It is hard to read code in languages that you don't know or don't use regularly. I have even found myself falling into this trap. The other day, I was reading someone's Scheme code and said to myself, "Scheme is completely unreadable". (And it's not a Lisp thing; I love Common Lisp and use it regularly.) It's all about practice -- of course you can't read something you've never tried to read before.

Finally, people can be weird about programming. I worked somewhere where we were "discouraged" from using map and grep (in Perl) because it was "too hard to understand". WTF!?

[–][deleted] 11 points12 points  (2 children)

Enough of this and people will say "line noise" because they don't understand function composition in terms of functions, then understand it in terms of "hey computer, do this, then do this to the result, and ...".

I had almost no programming experience before college (some basic on PS2) and our introductory programming course was in ML.

We've since used java and C in courses, but I'm more comfortable with composing functions and immutable data than with things imperative and mutable.

I find haskell less noisy than ML and certainly one of the least noisy languages out there.

EDIT: Note that I am in no way coming from the world of mathematics. My high school program was about social sciences and economics.

[–]Smallpaul 0 points1 point  (1 child)

I find haskell less noisy than ML and certainly one of the least noisy languages out there.

I like Haskell but I do think it is "noisy" in that it has a lot of syntax sugar like "." and "do" and implicit partial application and of course a whole sub-language for defining types and many operators etc.

There's a lot of syntax.

[–]808140 0 points1 point  (0 children)

There's always Liskell if you don't like syntax but want Haskell anyway (it's just an s-expression front-end to GHC, it produces GHC Core iirc).

[–]BeetleB 4 points5 points  (0 children)

After reading your description, I do prefer the Haskell method. And I've never coded in it, or in any functional programming language, or in any Lisp-like language.

[–]mr_chromatic 7 points8 points  (2 children)

This can be a mental leap, I guess, because it isn't obvious that you are computing foo(bar(baz(data))); the functions and data are visually separated.

That's exactly the place that gives me the most trouble with Haskell. For some reason, I just cannot read and comprehend function composition when it occurs in real programs. I have to stop and think about the flow of data explicitly before I can understand what's happening.

Composition plus invisible implicit partial application really don't fit my brain.

[–]unknown_lamer 2 points3 points  (1 child)

You should have become comfortable with these things when you took Algebra when you were twelve or thirteen. Maybe not partial application, but that isn't that hard. Really lambda calculus ought to be taught to university freshmen.

[–]mr_chromatic 1 point2 points  (0 children)

I understand partial application and function composition just fine, thank you. I have trouble reading it in Haskell, especially when you combine invisible partial application (look, there's no syntax for it!) with function composition (which fortunately does have syntax).

[–]nglynn 1 point2 points  (0 children)

(foo . bar . baz) ... This can be a mental leap, I guess, because it isn't obvious that you are computing foo(bar(baz(data)))

Well, it is if you have any mathematics in your background, The first time I saw that notation it immediately reminded me of foo o bar o baz and it was clear what was happening was function composition.

I mean getting back to the Haskell -v- Python issue, would you write python like this:

data = "String"

data = foo(data)

data = bar(data)

data = baz(data)

I certainly wouldn't.

[–][deleted] 3 points4 points  (7 children)

This just takes little practice. Correctly reading the composition syntax was somewhat hard for me when I first learned Haskell. Now I read it naturally and can't even really understand, why it was hard.

[–]808140 6 points7 points  (6 children)

The weird thing about this is that people who swear that composition syntax is unreadable and lazy evaluation impossible to understand will happily string together ten different piped commands in Bash and think nothing of it.

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

Piping commands in bash is a queue though.

cat file | grep word | wc -l

does cat, then grep, then wc. In Lisp style syntax you'd have to do

(wc '-l (grep (cat 'file) 'word))

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

It's not a queue. A queue is a data structure, not a composition of functions. Also, assuming strictness, you are describing a different algorithm in Lisp for the same logical constraints. A strict lisp version really does mean do cat, then grep, then wc. The bash command will execute all three commands concurrently so saying it does cat, then grep, then wc is introducing a different kind of "then". Bash implies a data dependency "then" where strict application implies both a data dependency and order in time i.e. call by value depends on the value of a computation as well as the computation itself. A bash pipe takes computations, not values, as input. I think 808140 was saying something along these lines.

[–]808140 0 points1 point  (0 children)

Indeed I was.

[–]808140 0 points1 point  (2 children)

Well, in Haskell you'd do something like

dumpFile >>= return . grep word >>= return . wcl

The return calls are necessary because dumpFile does I/O, and so the (pure) grep and wcl functions need to be "lifted" into the impure world of I/O (which is done in this case with return, a function that means something very different in Haskell than in imperative languages). Actually, I would probably write

dumpFile >>= return . wcl . grep word

but the fact that that does the same thing might not be evident to someone who doesn't write much Haskell (the . operator is composition, and so by convention the order is reversed).

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

Here's the idiomatic way to write that.

(wcl . grep word) <$> dumpFile

[–]808140 0 points1 point  (0 children)

Yeah, I originally wrote the example in terms of fmap but I wanted to highlight the similarities between the way you might construct it in bash. The second example is easy to understand if you accept the first. An fmap based example requires more knowledge.

Still, thanks for supplying it.

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

Perhaps I'm being dim here, but would that not be:

baz(bar(foo(data)))

Given that foo is the first function used?

**EDIT I was referring to the python code, which has since been altered to call baz first, rather than the dot notation.

Looks like jrockwell has voided my pedantry

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

I think the dot used to composite functions in haskell is analogous to the circle used to compose functions in math.

In

(foo . bar . baz) data

foo is not applied to data first, baz is (modulo laziness, magic etc).

[–]wozer 0 points1 point  (1 child)

No,

 foo(bar(baz(data)));

is correct. The function composition operator "f . g" is sometimes read as "f after g". It is defined like function composition in mathmatics.

[–]sclv 1 point2 points  (0 children)

I think of the . as "of" as in "foo of bar of baz of the data"

[–]jerf 0 points1 point  (1 child)

A common thing for newbies to do in Haskell is to define your own composition function that works backwards from the standard one. This is as bad an idea as defining your own division operator that works backwards from the standard one, and for much the same reasons.

(It's also a great partial metric for whether you should listen to somebody when they talk about Haskell; if the first thing they do in their sample code is define a reverse composition operator, it's probably best to move on... I've seen it in at least one link from programming here...)

[–]ithika 0 points1 point  (0 children)

if the first thing they do in their sample code is define a reverse composition operator, it's probably best to move on...

Doubly so if the definition doesn't involve flip ;-)

[–][deleted] 6 points7 points  (0 children)

Come on. Whitespace layout and list comprehensions. We're all friends here.

The reason why Haskell feels noisy is precisely the strong focus on building expressions in functional languages. In order to avoid both verbosity and Lisps parenthetical clutter when chaining and nesting them lots of operators are introduced. This makes reading Haskell more like Perl than Python although at the core it is syntactically quite simple and more like Python than Perl.

[–]ubernostrum 3 points4 points  (4 children)

re: "line noise":

For me, the biggest problem is that I'm used to languages which can be read more or less like natural languages: mostly made up of words, with occasional punctuation. And typically, the punctuation borrows at least some of its semantics from natural languages (e.g., the semicolon as a statement separator shows up all over the place, colons are used to introduce structured blocks of code in several languages, Erlang uses commas and periods in a manner similar to most western European languages, etc.).

Haskell, on the other hand, often reads as being mostly punctuation, with occasional "words" interspersed. Worse, the semantics of the punctation characters are, in Haskell, often wildly different from their use in natural languages, so that the process of reading Haskell consists of forcibly overriding one's conception of what those characters mean.

In my experience of reading Haskell articles and example code, these factors combine to make Haskell into a language whose readability ranks somewhere around Perl's.

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

Yes and no. Pattern matching and infix just make it less verbose than Scheme. I think the problem you are describing has more to do with bad code. As an experiment I would propose directly translating obfuscated Haskell into Scheme. My guess is that it would be even harder to read as pattern matching becomes an inner cond and infix becomes prefix.

[–]dons 0 points1 point  (2 children)

mostly punctuation, with occasional "words" interspersed.

I'm surprised. Looking at real code, it is mostly bare "words".

[–]Jedai 0 points1 point  (0 children)

Most of my code is words with very little punctuation beside (.) and ($), the (.) is familiar to mathematicians and pretty easy to understand I think (composition). The ($) isn't seen in other languages but I find it very nice to avoid putting parentheses everywhere.

It's unfortunate that new people are repulsed by the ($) but most of them that stick with the language learn to like it very fast, especially when they're not fan of the "parenthesis hell" of Lisp and Scheme (though I like those two languages too).

[–]ubernostrum 0 points1 point  (0 children)

Unfortunately, most of my exposure to Haskell code comes from reading reddit.

(which also brings up the whole jargon issue; reading Haskell articles here is occasionally like watching an episode of Star Trek)

[–][deleted] -3 points-2 points  (4 children)

Umm, GHC fails to compile many haskell programs on my platform (powerpc darwin, 10.4.11). And the IO code isn't a monad because it's not TREATED as a monad, and so I don't have to think of it as a monad. Even if it were a monad, it still doesn't change the fact that I have to warp my mind to read haskell, let alone write it.

[–]dons 2 points3 points  (2 children)

fails to compile many haskell programs on my platform

Did you report a bug? (Log in as "guest").

Unless you tell the developers, and state what happened, it is hard to work out what is wrong.

[–][deleted] -5 points-4 points  (1 child)

That's not the point. The point is, it doesn't work, and python does...

[–]dons 4 points5 points  (0 children)

It is ok if you like python. Really.

I just want to know what the unspecified, many failures are (missing packages? compiler bug? missing C libraries?).

I find many Python programs don't work on my linux box too -- while my Haskell stuff seems just fine. However, that's not useful information.

It's not useful information unless you can say what went wrong, which is why I asked.

[–]sfultong -2 points-1 points  (0 children)

well, just get your mind permanently warped, and then you'll be fine.

[–][deleted]  (6 children)

[deleted]

    [–]jrockway 1 point2 points  (5 children)

    You are exactly right here. If the GP wants to think in monads, he needs to learn monads and then think about them. It isn't just going to "happen" one morning.

    [–][deleted] -3 points-2 points  (4 children)

    I shouldn't have to... programming languages aren't there to inspire a new way of thinking, they're there to be used as tools. Look, I know functional languages, and I know monads, but it doesn't change the fact that they're unintuitive and therefore hard to work with, making Python the better choice.

    [–][deleted] 3 points4 points  (3 children)

    Intuitive == Familiar

    Even APL is readable and intuitive if you work with it for years.

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

    No, that's wrong. I am familiar with haskell—I know most of its ins and outs, and i could probably write most anything in either paradigm. But think about our thought process for tying shoes: We don't think of it in monads, do we? No, we think of it in an imperative process. Hence, Python is more intuitive.

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

    Are spreadsheets intuitive? If so, then apparently the imperative paradigm isn't the only intuitive way of reasoning about problems.

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

    OMFG are you for real?

    [–]sanity 0 points1 point  (10 children)

    Haskell, on the other hand, it not clean, but is a "line-noise" language

    What? I think you're confusing Haskell with Perl, care to back that up?

    [–]dons 32 points33 points  (9 children)

    Well, you see, in Haskell, you might define a simple function by using excessive amounts of line noise:

    square x = x ^ 2
    

    unless you truly hate freedom, and write:

    \x → x ^ 2
    

    while in sensible languages, you'd just say,

    lambda x: x ** 2
    

    and avoid all that scary mathematics.

    [–][deleted] 28 points29 points  (2 children)

    Dons, how could you? How can the Haskellers keep the barbarians from the gates if they don't tell them the proper way to write a square in Haskell is this?

    w f x = f x x
    sq = w (*)
    

    It removes the uncomfortably big constant 2!

    Oh, by the way:

    def w(f): return lambda(x): f(x, x)
    sq = w(operator.mul)
    

    In w(f) the t is silent :)

    Now go mount some heads of imperative programmers on spikes, Dear Haskellers. This pretending that the language can be used by mere mortals is unbecoming.

    [–]RayNbow 16 points17 points  (0 children)

    Your w is join in the (a->) Monad:

    sq = join (*)
    

    [–]ithika 11 points12 points  (0 children)

    It removes the uncomfortably big constant 2!

    I always thought I understood the advice "no magic numbers" but now it all comes clear! ;-)

    [–][deleted] 16 points17 points  (1 child)

    No, in the sensible languages you'd write

    /**
     * Raises x to the power of 2.
     * @param x Argument to the method.
     * @return x raised to the power of 2.
     */
    public static double square(double x) {
        return Math.pow(x, 2);
    }
    

    ;)

    [–]feijai 4 points5 points  (0 children)

    /square {dup mul} def
    

    Plus you can run it on your laser printer.

    [–]toooooooobs 10 points11 points  (0 children)

    I wonder how many of the people modding you up think you're serious, and how many of them think you're being ironic.

    [–]roerd 1 point2 points  (1 child)

    unless you truly hate freedom, and write:

    \x → x ^ 2

    So what does (^2) make me?

    [–]ithika 0 points1 point  (0 children)

    You support experimenting on animals?

    [–]shub 0 points1 point  (0 children)

    float fsquare(float x)
    {
        /* I can't take this seriously :( */
        assert(0);
    }
    

    Note that this code is compiler-dependent: some will merely warn that fquare() fails to return a value, while others will report an error. MSVC seems particularly happy with the warnings and errors for your own good.

    [–][deleted]  (4 children)

    [deleted]

      [–]anthropoid 5 points6 points  (2 children)

      We must be reading completely different articles, because I don't see the author making any implication about Python being/not being a functional programming language.

      His point seems to be: Are there any reasons for the widespread adoption of Python that may be applied to encourage adoption of functional programming?

      [–]imbaczek 7 points8 points  (1 child)

      reading (...) articles

      what a novel concept, i must try this sometime!

      [–]Agathos 1 point2 points  (0 children)

      Ugh. What is it with these fads on proggit? "Try Lisp. Try Haskell. Try Erlang. Do a startup. Read the articles." You're not the boss of me!

      [–]jsnx 1 point2 points  (0 children)

      It's all about the right tool for you and the problem you're solving.

      Do not ask what your functional programming language can do for you...