Why isn't Haskell popular in industry?
palgorithm.co.uk
palgorithm.co.uk
Haskell is a significant departure from most other languages commonly used by industrial programmers. It's a relatively shallow learning curve from Java to Python to JavaScript, but making the leap to a pure functional language is very difficult. Path-dependence plays a huge part here. This isn't just a matter of "people being afraid of what's different" as the article suggests; there are very rational reasons for a profit-seeking firm to exploit the fact that their developers (and those available to hire) are already relatively proficient at writing procedural code.
Another, more important reason, is that Haskell is too intellectually demanding for most industrial programmers. I consider myself an enthusiast of functional programming, but achieving anything practical using purely functional code remains extremely difficult for me, even though I regularly dabble in it during my free time. The Haskell IRC channel can be helpful, but it's very difficult to square "Haskell is easy enough for anyone to learn" with the inevitable "you are too stupid/impatient/incompetent to use Haskell effectively" taunts you're likely to hear, when you're asking for help to perform a simple task. Many Haskell evangelists don't understand that most developers aren't nearly as smart or dedicated as they are.
I'd be curious to know where most Haskell users believe they lie on the distribution of programming ability. I'd estimate most of them lie at the 99% percentile, and that any of them arguing otherwise are doing so out of modesty. (Note that I'd include dedication and curiosity in with intelligence in this metric.) I believe the most likely explanation for this is that Haskell is a particularly difficult language to use effectively.
While that's often stated as a reason, I don't believe it myself, simply on the grounds that anyone smart enough to use C++ "in anger" is smart enough to learn any language.
The reason that Haskell isn't popular (IMHO) is that a lot of programming isn't clever algorithms, it's forms (interfaces for getting data into databases) and reports (interfaces for getting data out of databases). A lot more is glue (connecting the output of one program to another). Haskell just isn't a good fit here.
I am very excited by F#; here we have an ML dialect that has minimal impedance mismatch with the OO/imperative world (and C# with LINQ has minimal impedance mismatch with the declarative world of relational databases). This is where Haskell types should look for work...
That's not to say that I think that it's intelligence that's lacking with respect to Haskell etc. I think the problem there is the mode and style of thinking, and that most programmers are too old to easily pick up the different way of approaching problems that it becomes second nature. That, and functional programming's chosen compositional breakdown of fixed common data with an open-ended set of applicable functions is not always as applicable as object orientation's breakdown of open-ended data with inheritance of fixed sets of functions; you often need to introduce an extra level of indirection (=> abstraction) with functional programming to get access to the dynamism that OO gives you in the box.
Well, with formlets and takusen you're pretty much sorted.
http://haskell.org/haskellwiki/Formlets
http://blog.codersbase.com/2010/08/takusen-tutorial-part-1-h...
My first Haskell project for work was initially a C++ project, but it was too hard to use C++ as a glue language, so I switched to Haskell. I would have used Perl, but Haskell works better on Windows and has an easier-to-use FFI.
I actually ended up spending more time trying to get some old version of Visual Studio to link against my super-old-proprietary-C-library that was the core of my project than I did writing the whole Haskell FFI binding to that library and writing the first version of the Haskell-based program.
This turned out to be the most trouble-free program I ever wrote. It had to operate on large datasets, and never died in the middle (like I'm used to with Perl). The only bug that the program ever had was where one of my data validation rules was too strict, and rejected some valid date. (The validation rule said that the dates in the time series had to be increasing. But one series only had one point, and hence wasn't strictly increasing. The bug resulted in "Warning: bad data", though, not "Prelude.(!!): index too large", as the implementation was with fold.)
Incidentally, as a result of this project, c2hs supports Windows DLL calling conventions :)
I actually have a problem like this right now; I'm starting re-development on an application whose components talk via CORBA over an ultra-expensive and ultra-overengineered proprietary message bus. My plan is to write a bridge between the proprietary message bus and JSON-RPC (or something like that) in Scala, and make the rewritten components only talk JSON-RPC. Then, when everything is rewritten, there is no more super-expensive-message-bus requirements, and we shut it off. Now we have the ability to write components in any language.
(Also, the reason this doesn't count as adding shit on top of shit is because eventually the ugly bridge will go away. That only exists to make the rewrite into a refactor. You have to have a scaffolding, or all the shit will collapse on top of you and make a big mess. :)
Now I know the reply is going to be, "well, not everyone can just replace their proprietary crap with something simpler and more generic", but again, that's not a Haskell problem.
Don't forget that F# was "inspired" by OCaml ...
http://cufp.org/archive/2006/slides/CliffordBeshers.pdf
They used Haskell's strong static type system to safely glue things together.
Excel is pretty much a functional language (though it is a little disabled), and people do amazing things in it.
The problem isn't that functional languages are hard. They are a bit different, but good code is often fairly functional anyway. The problem is that most of the community seems to be obsessed with showing that functional languages are both better, and more difficult, than mere procedural languages.
Take monads. The only way to "get" monads is to realize that they are just sections of the program that are imperative. But most Haskell programmers introduce them in the most incredibly obscure double-talk, just to avoid admitting that Haskell needs the ability to do imperative things in order to be useful.
A monad is a very nice container abstraction - period.
The IO part of Haskell just happens to leverage monads. One of the benefits of which is an explicit marking of impure methods in the type signature, but there are others.
Monads are used in plenty of purely functional parts of Haskell.
Disclosure: been programming Haskell for only a few months now, so someone pull me up if I'm wrong. However, I have used a lot of monads so far (and they're not hard, its just a higher, more convenient level of abstraction).
edit: to address your post further. I honestly don't think that the community is the reason that Haskell isn't taking off. If you were to gather stats on the points at which would-be Haskellers give up, I think most people would leave 1) when they can't grok the syntax easily or 2) when they can't get tools or libraries going easily (it was a problem for me) and long before they get to the point of visiting the news groups and start running up against academic-type people.
Say you're working with the Maybe type, which is often used to represent operations that might fail, such as a map lookup, for example.
data Maybe a = Just a | Nothing
We're using two functions defined like so (feeling unimaginative at the moment, forgive me): x :: String -> Maybe String
y :: String -> Maybe String
We want to use them together. Someone who's not familiar with monads might write something like this: myFunction text = case x text of
(Just newText) -> y n
Nothing -> Nothing
(If x works and returns a value, put that value into the y function. If x didn't work, just return Nothing)It works fine, but imagine you had 3 functions that returned Maybes, it would get tiresome and messy nesting all those case statements endlessly.
[...]
case x text of
Just newText -> case y newText of [...]
Not being satisfied with boilerplate, lets make an operation that will simplify this a bit: bind :: Maybe a -> (a -> Maybe b) -> Maybe b
bind (Just x) f = f x
bind Nothing _ = Nothing
now we can define myFunction like so: myFunction text = (x text) `bind` y
if we want to add another operation: myFunction text = (x text) `bind` y `bind` z
Congratulations you've mostly made a monad. Bind is one of the monad operators (>>=), the other operators are extremely trivial to implement for the Maybe type.This is why we say a monad is just a container with some handy operators. Maybe is the container, and bind is a way to chain together operations (without explicitly taking the value out of the container) so the operators themselves don't have to know anything about the nature of what they're dealing with.
I won't bang on anymore, this is a longer, better written tutorial[1] in the same vein as this short summary.
[1]: http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
Are there use cases for Maybe where you're not interacting with some sort of IO?
elemIndex :: a -> [a] -> Maybe Int
lookup :: k -> Map k a -> Maybe a
Say we have a map of lists of string, for some reason. We need to find the index of the element "foobar" in a particular key, so you could write: lookup key map >>= elemIndex "foobar"
(a simple example for the sake of brevity)Not very impressive, but monads aren't anything groundbreaking after all, they're just utilities that make our lives easier. There are more complicated operations that come in handy later, but they are quite straightforward once you get a grasp of the container metaphor.
Would it also make sense to use Maybe monad for converting a [Char] to an Integer?
stringToInt :: [Char] -> Maybe Integer
Let's use the List monad to determine someone's roommates.
> import Control.Applicative
> import Data.List
First, the data: > type Person = String
> type Address = String
> addresses :: [(Person, Address)]
> addresses = [("jrockway", "123 Fake St."), ("jrockway's cat", "123 Fake St.")]
> people :: [(Address, Person)]
> people = uncurry (flip (,)) <$> addresses
And some helper functions around this data, a function to return all
addresses for a person, and a function to return all people that live
at a certain address: > assocFilter :: Eq a => a -> [(a,b)] -> [b]
> assocFilter p xs = snd <$> filter ((==p) . fst) xs
> addressesForPerson person = assocFilter person addresses
> peopleAtAddress address = assocFilter address people
To find a person's roommate, we have to chain two computations.
First, we have to find zero or more places where a person lives. Then
we need to find who else lives at each of those addresses. With the
List monad, this is not much code! > roommatesFor :: Person -> [Person]
> roommatesFor person = do
> address <- addressesForPerson person
> peopleAtAddress address
The monadic combinator >>= (which is hidden by do) does all the looping for us, so we don't have to explicitly write it out.BTW, you can just cut-n-paste this into a .lhs file and run it, if you want to try it out.
map (* 2) [1,2,3,4]
Yep, that's a function on a monad — lists are monads. The same function can be written: [1,2,3,4] >>= return . (* 2)Not really. Monadic function composition is just like regular composition, except that the programmer is given the ability to make "f of g of x" do something more than just pipe the result of g(x) into f. This can look like imperative programming, but it's still purely functional.
If you're willing to call monads Kleisli arrows instead, then you can even the same syntax to chain monadic computations as "regular" computations.
For example, write a function to add one to a number, then multiply by 4:
f :: Num a => a -> a
f = (*4) . (+1)
That's a normal function, with the normal function composition operator.Now write a function to increment the state, in a stateful computation, by a number:
inc :: Int -> State Int ()
inc x = put . (arr (+x)) . get
Even though State is a monad or Kleisli arrow, you can treat the stateful computation as regular function composition, because it is just composition. There is no imperative programming anywhere to be seen. Although operating on some hidden state feels imperative, it's not. (Under the covers, it is a bit different than what you might be used to. Each stateful function is really a function from its arguments to another function from the current state to the result. We compose the "result" functions into one big function from state to result. This involves a bit of plumbing, but the actual implementation is only two lines of code. And it makes for a very useful abstraction in many cases. But I digress...)Monads are just a way to make similar things, chaining computations with an arbitrary combinator, look similar in your code. We did it with State above, and there are lots of other things that work similarly. Computations that can return zero or more results, computations that can fail, computations that operate on transactional memory, etc. We use "Monad" (or "Arrow") to provide the programmer with a common syntax for interacting with each. That's all a monad is.
(IO is weird, and it is a monad, but it could also be an applicative functor, or comonad, or arrow, or a lazy list, or. Don't extrapolate your knowledge or fear of the IO monad onto monads in general.)
It is of no help or use to those who do not understand monads that they could also be an applicative functor, or comonad, or whatever. You may be perfectly correct, but for someone who is not already part of your community, and conversant in its terms, it does not particularly help.
-- | Kleisli arrows of a monad.
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)
I only brought it up to show that we can use the same operator, Control.Category.., to compose functions, monads, and arrows and that they are not all that different from each other.(It's also worth noting that every language has their own language-specific terminology. If I Google for "std::string", I am only going to find C++ results, despite the fact that strings are a generic concept. If I search for "IEnumerable", I am only going to get C# results, despite the fact that enumerations are a generic concept.
Similarly, not many languages think of programming in terms of arrows and objects and categories, so you don't see many results for "Kleisli arrow" outside of the Haskell community.
But http://en.wikipedia.org/wiki/Kleisli_category is to category theoretical monads as Kleisli arrow is to Monad in Haskell.)
So far as I can tell monads are abstraction of state(though calling them abstractions of function application is more correct, calling it state is more intuitive to me, and how they are represented in the type system.) From there they get used for different things: Maybe == Nullable Types, List == lists, Either == Unions, St == Mutable State, IO == hide IO. Then a function that is pure and doesn't know about what your monad does gets invoked by the monad where the hidden state changes the flow of computation. Maybe performs a null check, List calls map, Either picks the type in the union then calls the function on that, St allows you to use and update the hidden state, IO performs IO then shares the result with you.
Now there is an explanation of a monad that doesn't assume you already know what a monad is. It may not be good since it basically says monads are sticky higher order functions masquerading as a data type, but there you have it.
Remember, you understanding Haskell will improve your understanding of the Universe. You understanding Haskell will do nothing for me. So you can see how the incentives are aligned...
The net effect is that your community is going to be composed of people who made a conscious effort to break through the communication barrier. This isn't necessarily a bad thing; you end up with a small, focused group of very smart people. But it doesn't buy you many converts in the industry.
When a function uses global state to compute a value, it's like the global state is an argument to the function.
When a function modifies global state, it's like it returns both the value it computes and the modified global state.
If you're interested more you can read http://research.microsoft.com/en-us/um/people/simonpj/papers... which I believe is the original paper introducing monads into Haskell. The first 11 pages are very approachable and give you the rational for why monads are necessary in Haskell and what they're for.
> If you're willing to call monads Kleisli arrows instead, then you can even the same syntax to chain monadic computations as "regular" computations.
I have no idea what any of that is meant to mean! Are you just trying to prove wisty's assertion that "Haskell programmers introduce them in the most incredibly obscure double-talk"?
(I used the term "Kleisli arrow" so that you could Google for something if you wanted to learn more. All you really need to know is that you can use . to pass the output of a regular function into the input of another one, and you can use . to pass the output of a monad into the input of another. Saying it that way is very imprecise, though, and the goal of people explaining things is to say them precisely so that you have some hope of eventually gaining an understanding.
You have to bootstrap understanding. Assume you know what a Kleisli arrow is. Then read the rest of the post. Now your assumption is correct!)
The thing to "get" about Monads are that they are a means to describe imperative things going on, in a way that blends in with not necessarily imperative things. Which is part of why it's so tough to explain them - we're all talking past each other regarding what "the point" of using Monads are. The point to them in Haskell is mainly twofold:
1) Haskell users can use a Monad to describe net access, DB access, file access, and other "once done, the results are out of your control" effects in the same way as describing using (Writer) computations that keep a log of what's being done, (Error) exceptions, (Reader) environment variables, (List) functions with multiple - or no - results, and more.
It's really easy...and kind of mind-blowingly complex, all at the same time.And since most average Joes just work to pay their bills, they don't give a damn about technical superiority, you know.
Let's consider Common Lisp. Newcomers and outsiders complain that CL doesn't catch up because there aren't free CL environments around with a thoughtless setup (I've been in this camp too). However, if you read comp.lang.lisp, it jumps into your eyes that many lispers are accomplished and sharp programmers. Still, they haven't fixed such "issues" once and for all. So, what's the real deal? I think that here lies an explanation: such issues are not such an issue to experienced programmers. That is, if you can't setup a CL system, you simply are not skilled enough as a programmer. Get over it. I think the same applies to other systems like Haskell, GNU/Linux, Emacs and so on.
What do you think? Thanks.
EDIT: Of course, there are other causes to consider... for instance, since most CL developers work on *nix, there is less work done on Windows. I think that installing a CL environment kind of fires the Law of Leaky Abstractions: you'll have to deal with some nitty-gritty details...
Not because they're not experienced enough or because in principle they can't make it work (I'm sure they could) but simply because there is only so much time.
If you haven't reached a certain level of confidence that a path is the right one within a given amount of time the natural thing for an experienced programmer is to abandon the path, after all, there are so many technologies to choose from that you can't afford to invest too much time into something that feels like a dead-end, even if in the longer term it might turn out to be great.
I can see your point, and I agree on principles. I disagree on "good documentation", "friendly community", "bug free implementation", "good libraries"... If there are either lacking of "good documentation" or "bug free implementation" or "good libraries", that just means a language either is academic or not ready yet for production, thus you'd better skip it. About "friendly community", I'd rather say that there are self-selecting communities. For instance, many people complain about "social problems" of Lisp, yet I had a very nice experience while asking even controversial questions on comp.lang.lisp.
> If you haven't reached a certain level of confidence that a path is the right one within a given amount of time the natural thing for an experienced programmer is to abandon the path, after all, there are so many technologies to choose from that you can't afford to invest too much time into something that feels like a dead-end, even if in the longer term it might turn out to be great.
That's why I've resolved to put my time only in both time and battle tested languages like Common Lisp and Erlang.
Thanks for sharing your view, Jacquesm :)
Each year there is new programming language or framework that "will change the computing". Oh come on. We all know that Windows will become lousy implementation of Unix. We also know that all programming languages eventually will have half-assed implementations of Lisp features. Why you should learn Haskell when Lisp is more superior?
• A powerful type system with inference
• Purity
• Pattern matching baked into the language core
• Full laziness (such that "if" can be written as a pure function, no need for special forms or macro-like functionality)
• Curried functions and partial application (so, for example, Lisp's (defun double (n) (* n 2)) would be double = (* 2) in Haskell)
But these things are unrelated! Your ability as a Lisp programmer is entirely unrelated to your ability as a Windows/Linux/whatever sysadmin/build engineer/whatever. If anything it's the old "it works on my computer" excuse that (bad) tech support trots out. That's the thing that sets the Clojure guys apart, they actually are interested in making it possible to take it for a spin.
I'm reminded of the difference between PADI and BSAC, two competing dive schools. PADI says let's get you in the water as soon as we can, don't worry, it's only a swimming pool and we have instructors and lifeguards on hand, and when you're ready we'll go out to sea and continue learning there. BSAC says study in a classroom for 6 months, then let's go dive a wreck at 50m...
Are we sure? Isn't this a case of Law of Leaky Abstractions? We may think we can and should ignore issues related to underlying hardware, but reality is we can't and we shouldn't. As programmers we need a bit of knowledge about system administration too, even when we are working on a virtual machine.
Kudos to Clojurers! Maybe there is more enthusiasm and understanding about newcomers in Clojure because it is a new language. That is, the are not under the Curse of Knowledge.
We should acknowledge that Haskellers are trying to meet the needs of newcomers too, by releasing the Haskell Platform.
"Can't" is not at issue here - with enough effort, anyone can do just about anything. The question is whether it's actually worth the effort.
Given a choice between languages A and B, both of which have very enthusiastic userbases that are utterly convinced that their language is the One True Programming Language, but neither of which I've actually spent enough time with to know whether it will be worth the investment, which one will I spend the time to learn to work with?
A smart programmer will pick whichever one gets up and running the quickest so that he can actually see what coding is like in that language, as opposed to configuring/installing/compiling sources/tracking down a supported version/etc. Why waste time doing all that stuff when if you just hop to the next language over you can have it all for free? Not to mention that problems setting up a dev environment are loosely predictive of future problems dealing with deployment, hiring extra hands, getting support when things go wrong, etc...
Common Lisp is getting its clock cleaned by Clojure because the Clojure folks know that lowering barriers to adoption is a critically important thing when people are faced with such a glut of choice.
But then again, I've never gotten the sense that the CL folks actually want more people using it, that community seems to be more than happy to remain an elite insider's-only club that is - obviously - smarter than everyone else. Which explains a lot of the hate for Clojure - it's bringing powerful tools to the unwashed masses, and it turns out they wield them quite effectively, shedding some serious doubt on the implicit assertion that you have to be really, really smart to use any sort of Lisp.
Perhaps I should have said "with little effort", then. If you can't setup a system with just little effort, you are not skilled enough as a programmer. See, Ewjordan, I understand your frustration. I've had my share with setting up "newbie-hostile" systems, and you know what? As a consequence, I now understand better how things work, and I can setup whatever system faster. I have "graduated" from Ubuntu to Debian user, I now use Emacs as my only editor, and so on. Little improvements... Still learning. Oh, and I'm faster at tracking down and fix issues which I or my coworkers stumble upon.
> A smart programmer will pick whichever one gets up and running the quickest so that he can actually see what coding is like in that language, as opposed to configuring/installing/compiling sources/tracking down a supported version/etc.
Would we really call her a smart programmer? A street-wise programmer maybe. Being such a programmer could be your goal? That's fine. Have fun and make a lot of money. I think a really smart programmer will pick the language which will pay more dividends in the long run. Kind of choosing a Vim clone over a regular editor.
> Why waste time doing all that stuff when if you just hop to the next language over you can have it all for free?
Because not all language are created equal and you sometime have to choose between fighting the system in the beginning and fighting the language in the long run.
Of course, you'll have an hear for practical considerations too. For instance, I'm currently learning Common Lisp over Scheme because even if I like Scheme better, CL has a wider user base and a proven track record.
> But then again, I've never gotten the sense that the CL folks actually want more people using it
I agree. Most of them don't seem interested. And I think I understand why. CLers are an old community and a lot of newbies jumped in, whined about things not working and left. Their hears are full. However, if you ask for help and ask for it smartly, you'll get answers, you'll - you won't believe this! - you'll get even code written for you.
P.S.: Sorry, but I don't have time to review this post. Bye.
I can't remember the last time I had trouble getting something done in C because it didn't support Kleisli arrows, or whatever.
Indeed Haskell lacks a proof of concept of its superiority. And you can't provide such a proof with a few lines of code.
When I studied Erlang, I was flabbergasted by both code size reduction and expressiveness thanks to pattern matching, by its fault tolerant capabilities, by its hot-code swapping... then reading how Yaws was alive and kicking long after Apache died under heavy load.
E.g. "I can't remember the last time I had trouble getting something done in Pascal because it didn't support pointers" :-)
Moreover, hating to feel uncomfortable about yourself is just a human trait and most people just like following the path of least pain (another human trait, I think).
Now if that isn't an insult I don't know what one is. You don't have to grok Haskell to live your life to the fullest(especially if your Domain isn't programming languages.)
Again, I don't mean using a dismissive tone. If it feels like that, that's just because I'm not a native English speaker, and I already struggle to say what I think.
I do think that many people taking it easy are sorely needed by society. Innovative minds do push our culture forward, yet armies of "average Joes" - who just take every day as it comes - keep up with day-to-day tasks, are loving and unselfish people, and so on.
And of course you don't need to grok Haskell or even programming to live your life to the fullest.
Not being interested in some smart subject does not mean you're stupid.
Peace.
Check out this paper for a discussion of these issues in a real world Haskell application:
Windows has C# and all that, and it works nicely for them.
Perhaps this leads to a wider question of who the Haskell audience really is and what problems they think they solve. Lots of languages have pigeon-holes, Ruby has its super dynamism, Python is an excellent scripting environment, C is fast, etc etc. Haskell is... mathsy. Mathsy applications already have Matlab and such.
I think at the end of the day, Haskell will probably remain a language from which other languages learn from, and that's OK, and that doesn't mean it's unimportant (I think even SPJ has said similar).
For example, I work at a Windows-centric shop, but if I could make a compelling case to build a tool/product on a different platform, I could get my boss to approve it if it didn't require a new piece of hardware. We have written tools in other languages besides C#, but we stick to languages that are easy to deploy on our current servers.
I would think Haskell is "mathsy" in a much different sense than Matlab is "mathsy"
I am running a Debian VM in VirtualBox for my Haskell work now... That's great when it's just me playing, but not so much for production code.
- Because it's not OO.
Why doesn't Java support pattern matching?
Objects are a way of implementing protocols without needing to know the details of the object that implements the protocol, even at runtime. Polymorphic code in OO systems is a runtime feature, not a compile time one; objects may be loaded dynamically and almost always are at some level in any large OO system, for configurability and testing if nothing else.
Also, I think what you're describing is the difference between parametric polymorphism and ad-hoc polymorphism.
class Base
Base(int i_init) -- constructor
virtual int f(int param) -- a method
class Inherit1 (extends Base)
int f(int param) -- reimplementation 1
class Inherit2 (extends Base)
int f(int param) -- reimplementation 2
class Inherit3 … (ad nauseam)
We don't need class polymorphism with inheritance, here. We can do simpler: class Base
Base(int i_init, int f_init(int)) { f =: f_init; … }
int f(int)
Or even simpler: int f(int i_init, int f_init(int)) // C-like syntax
f: int -> (int -> int) -> int -- Haskell syntax
(And don't tell me that passing function as parameters is weird, or complicated. Functions are typically way simpler than "Objects".)Why can't Haskell make it easier to express data structures? Something "turtles all the way down" introspective, like a MOF (meta-object facility, http://en.wikipedia.org/wiki/Meta-Object_Facility) would be nice.
Most languages undergo a "fad period", where it's hip and cool to write in it and people just do it because other people do it. Clojure is going through this right now, as are Scala and (arguably) Haskell.
We'll just have to see. I honestly hope Haskell becomes popular. Judging by http://shootout.alioth.debian.org/u32/haskell.php, performance really isn't an issue. It's more of just an issue of programmer adoption and a willingness to throw yourself out there to spend some time to learn how to think outside of the imperative programming box.
I want to add that he was just the first guy that popped into my head when I thought C. I questioned it at first too, but the more I thought about it, Linux itself could have just as well have been written in Pascal or Lisp. If it had been, perhaps a lot of the tools, drivers, etc that interact with Linux would've been written in that language as well?
Perhaps a better example is needed.
Similarly, I don't think C++ was ever obscure in that it was widely publicized as the "next" C and people were pretty keen to use it - it was more that the early tools for C++ failed to live up to the initial promise.
(not attacking the OP, I'm not convinced yet one way or the other on the topic, just saying that when someone is called on his arguments and methodology the refutation in an intellectually honest discussion shouldn't be vigorous hand waiving).
http://www.reddit.com/r/haskell/comments/cs54i/how_would_you...
Writing a quick directory traversal function should be a no-brainer in any reasonably general-purpose language. The fact that the above reddit thread is jam-packed with the ins-and-outs of doing this simple task in Haskell tells me that Haskell may be great for some things, but it's probably not general-purpose, or a great fit for anything close to the heavy I/O, streaming, processing sorts of code I write.
I actually own Real World Haskell, and have tried off and on to get into it, but I found that Clojure 'took' in my brain 1000x more easily than Haskell. It's a real bitch, because I'd love to be able to say I can write Haskell, but gosh-darn it, I just can't. Grrr. Sigh.
quick edit: in answer to your point about a 'killer app' for Haskell, the parsec parser-combinator library looks bloody brilliant. Maybe if I run across a parsing need, maybe it'll help me get something useful out of Haskell, but I suspect my brain just doesn't get on with the Haskelly/MLy languages.
This is going to sound like an odd analogy, but saying "I won't use Haskell because I want to do IO, but don't want to unsafely do IO", makes you sound like a person playing a fighting game who blames their loss on the game not being "fair." If you're playing to win[1], and there's an "unfair" tactic, you use it yourself. If "cheating" at Haskell lets you do a higher-quality job, faster, than either using a different language or "playing Haskell as it was meant to be played" (i.e. being a scrub) then why not?
What people need to learn is that you don't have to do that for everything. You can have all the advantages Haskell brings while not trying to make everything in sight into arrows and co-monoids; if it's easier to do it the non-idiomatic way (i.e. the way that doesn't involve turning your easily-expressible business domain into difficult-to-express Mathematics), then do that part that way, and get back to work.
Most programmers are not mathematicians (especially self-taught ones) since at the end of the day common programming tasks don't require you to know advanced math (I'm not implying knowledge wouldn't be very beneficial).
I think Haskell is for those mathematically oriented both because only mathematicians would have cared to wrestle with monads to achieve purity (Clean is as pure as Haskell, with no monads in sight) and because its notation, whose succintness matches that of maths.
I confess I've been scared of Haskell's heavy leaning on operators and many levels of precedence among them. I prefer more verbose languages. I'm not mathematically oriented, I think.
Have a nice day.
When people in that reddit thread started debating zygohistomorphic prepromorphisms, even I assumed it it was reddittard parody. Apparently not!
it's a straightforward lifting of the non-monadic version. You can almost get
it from g_hylo by using the identity comonad, it's distributivity law, the
identity natural transformation, and using T.sequence as the monad's
distributivity law[1]. But this doesn't quite get us there because it requires
that we can refactor the monadic parts of the coalgebra into the algebra.
http://www.reddit.com/r/haskell/comments/cs54i/how_would_you...Other languages use weird terminology, too: "public static void main"? How about "pure virtual destructor"? "Visitor"?
The natural way to do this is to use an unfold to
generate a list or tree of all the files in the
directory tree, map over them to get the sizes,
and do a fold to get the total.
-- And similarly elsewhere, more explicitly, as he makes clear why he isn't interested in the 'obvious' solutions, e.g.: Yep, this is a good practical approach if I just want
to "du". I'm looking specifically for the fold . map .
unfold approach ...
The interventions of doliorules and then winterkoninkje (whom you quote) were in fact the ones that spoke to his condition.If you asked any question in the form of, "how do I write <non-trivial program> in <any langauge>", and you aren't paying for a week of someone's time to get you a really good answer, you aren't going to get a really good answer. It has nothing to do with Haskell. The reality is that programming involves trial, error, and iteration. People on Reddit can give you good first-drafts, but the final product is up to you. (If you asked, "how can I write du in C", then someone could just paste the source code. But du isn't necessarily the best implementation of du.)
I've written some directory traversal code in Haskell for a work project, and I didn't find it to be particularly mind-bending or difficult. I did it the same way I would have in Perl or any other language; visit directory, run my computation, collect the answer, recurse.
maybe I'll test them out and do a little blog post on the subject
I strongly feel that if Ruby was just Rails, it would have petered out by now (maybe people might have even gone back to Perl and CPAN). I think that GitHub may well be the driving force behind Ruby at this point. GitHub gems are pretty decent, but like the OP points out, Haskell packages aren't.
edit: just noticed a discussion about this exists already. That'll teach me to read all the comments in future :)
Long before Linus came along C was the programming language of choice for anything from games to operating systems and so on.
I program both on desktop and on web.
On desktop I program C# which is mediocre and recently I have started using C++ with Qt. Qt has huge advantages over C# (QtCreator is IDE that is going to be better in time than Visual Studio, currently it lacks few features, but still I find it usable). On both languages I have my set of libraries which you can't find everywhere else and make my life easier.
On web I use php and sometimes I use Rails. Each has advantages, I use php cause I've used it since php3 so a lot of historical baggage. On each I have my set of code and libraries I use the most.
So lately there's a whole new languages and frameworks coming out. Why should I spend my time porting my libraries to Haskell? Do I get significant advantage coding in it? No, because I use mostly my own libraries.
For a variety of reasons — including critical third-party libraries — anything that doesn't run on the JVM and interoperate with legacy Java code is just a non starter for my company. I suspect many other organizations are in a similar situation. It looks like someone is working on a JVM port now so hopefully we'll see something usable in a few years.
It succeeded.
I appreciate the fact that Haskell's designers don't look down on "average" programmers like the Java designers did but I think it's sad that they don't look at all.
>max = head . sort
Due to the laziness, the above will find the max entry in O(n) time, just like your hand written loop would. How can you not find that beautiful?
Now I do agree that they often seem to use too many symbols that look like other symbols but the few times I've investigated it actually ended up making sense (e.g. Arrows).
I assume you're pointing out that I have my sort backwards but I was being intentionally as ambiguous with this part because it's not relevant to the point I was making.
Yes, it's triggers my Rainman instincts to point out that 1. It should be max = last . sort 2. Or min = head . sort 3. You are making assumptions on the sorting algorithm to make it possible to short-cut the evaluation.
K-MART! K-MART! :)
Edit: How nice of you to downvote...
I think you should be more careful with following conventions. Everyone knows sort sorts ascending.
However I think that you didn't pick the best example.
I tried out:
>head $ sort [1 .. 10000000]
6 secs, using ~2g of heap! (actually is should be a reverse sort)
and the "hand coded loop":
>let mx (x:xs) m = if x > m then mx xs x else mx xs m; mx [] m = m >mx [1 .. 10000000] 0
3 secs, heap usage stays negligible low and constant.
Something is clearly not behaving as you depicted.
(of course my 'loop' code is not the exact equivalent of the last.sort composition, since it requires a 'minimum' parameter to be passed in advance, which not all types have. On the other hand it works also for the empty list)
I also have the feeling that, unless special compiler optimization (a very 'specific' one, I fear), the simple application of the 'head' function to a sorted list would stop when the first result element is produced, which is not after O(n). Granted, you don't have to wait for a full sort, since the sorting algorithm could guarantee that the rest of the list contain 'lesser/bigger' elements only and thus stop. But keeping track of all this should be space consuming, in respect to a simple linear scan.
Anyway the space problem of the "lazy" solution is a bigger issue than the number of comparisons.
I'm not a haskell master, but if I got it right, one of the mayor problems of lazy programming is that in some situations it can degenerate to a huge amounts of "unevaluated thunks", which are frozen computations yet to be performed, but which require some state to be held in memory (like function arguments, I guess).
(http://www.haskell.org/haskellwiki/Thunk)
or in this case, the space usage is caused simply because the list has to be materialized in memory instead of be simply traversed and generated on the fly. (but 2g seems slightly too much).
Anyway, the point here is that the two methods are not equivalent.
I think that understanding the impact of laziness on space is an issue that certainly increases the learning curve, as it requires time to master this and other optimization techniques if you want to get predictable performances from haskell.
(BTW, I actually use haskell for work, perhaps in a slightly conterintuitive way. I use haskell for quick prototyping ideas and solutions. Sometimes I get inspired by the solution I end up with haskell and translate it in clojure or java (work requirement), or at other times I have to rewrite it completely, but the possibility to quickly prototype in haskell really helps me a lot. I would love a stable ghc JVM backend.... it would change my life)
http://apfelmus.nfshost.com/articles/quicksearch.html
As far as I can understand from the blog and and the cited mailing lists, it works but it requires a carefully coded sorting method, otherwise O(n log n) as expected.
Sort specifically was (I felt) a small part of my point but I should have known that on a "hacker" site one must be exact. :)
I found a fascinating examples of the expressiveness and beauty of haskell due to lazy evaluation, which I think is better suited for FP evangelism:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Here we are defining the fibonacci sequence in a declarative way, recursing with a recursive "call".
The way the 'fibs' function is coded directly reflects the definition of the fibonacci sequence itself:
The 'fibs' list is defined as a list containing the first 2 elements and then, as a tail, the result of the application of the + function on the previous pair of elements.
"You can borrow things from the future as long as you don't try to change them"
It's always the same reason why people dislike new languages. People don't realize, that they can't look open-minded at a new language, if they already know a language. Because they will always compare the new to the already known language.
Most people are only open-minded if they learn their first language, after that, everything else is just ugly compared to the first one.
You just can't decide if something is ugly, until you have learned it, understood the meaning of the syntax, how all the single parts of a language fit together.
Haskell is nothing like Perl. It's one of the most beautiful and well-thought-out language I saw until now. Absolutely nothing compared to the auto magic of Perl.
Its even better when you understand it more. The syntax brilliantly expresses the fact that you're essentially working with a computerized lambda calculus.
http://www.codexon.com/posts/why-arent-functional-languages-...
Short version: Haskell is harder than C while being slower and uses more memory. The main implementation GHC, comes with GPL concerns.
And as pointed out at the time, commercial users already funded the -dynamic flag, along with the ability to swap out libgmp.
So that's FUD. As was pointed out in this forum at the time: http://news.ycombinator.com/item?id=847120
These days you can just run "cabal license-check" (IIRC) which will type check all the libraries you use for compliance.
Have a nice day.
You and your supporters succeeded in bombarding every article that even mentions Haskell the wrong way with snide comments, and probably won over a few hobbyists. At the end of the day though, the managers making the decisions will not think "Don Stewart said so, it must be true". They will find the same conclusions that Jon Harrop, myself, and other people you have ostracized have found. And this will continue until it even if you succeed in suppressing all negative feedback on Haskell.
Have a nice day.
"Don Stewart said so, it must be true" actually isn't such a bad heuristic (as far as Haskell is concerned). From what I've seen, Don is quite cautious.
This is not surprising coming from someone involved with Haskell. Do I really need to point to you the bug ticket that it was only 8 months ago that you could use something other than GMP? http://hackage.haskell.org/trac/ghc/ticket/601
Even with the option to dynamically link, it still doesn't change the fact that it was the __default__. And what a scary default that was. Company lawyers don't like to touch anything related to GPL with a 10-foot pole, for the reason that it is really up to the jury to decide what is a "derivative work" even if you only link dynamically! Maybe if you live in France, or have a 5 person company, this is an acceptable state.
Anyway I am done, you and Dons win, are you happy? I simply have no ulterior motive or incentive to defend my findings against organized groups who have their livelihoods and PhDs based on Haskell.
Now it's a pity that companies are scared of the GPL. As far as I know, most software is custom or private, is never released[1], and thus can't possibly infringe the GPL.
I think the real problem here is corporate culture. No company would object using the glibc in a proprietary program. So why would they be scared of any other LGPL library? When they don't even release the software? That's plainly irrational.
Now our choice is hard, but simple: get rid of the "GPL == we can't use it" line of thinking, or get rid of restrictive licences.
[1]: Many custom software actually belong to the company that wrote it, rather than to the company (or government) that purchased it. In this case GPL infringement could happen. But really, I can't fathom why some customers still don't demand complete ownership (including source code) for their custom software. That strikes me as either wildly misinformed or incredibly silly.
You aren't really an outsider considering your participation in the Haskell Cafe mailing list and being credited in Real World Haskell.
And companies do object to using glibc in a proprietary program obviously. You are probably thinking of the GCC runtime which has an explicit exception for commercial programs that prevents them from turning GPL.
http://www.gnu.org/licenses/gcc-exception.html
You also don't have any proof that most software is custom or private. Even if it is the majority, you cannot deny that the shrink-wrap industry is huge, especially during most of Haskell's existence. The answer is to avoid GPL code in the language which is what I was saying the whole time. You don't put the foundation of your business at risk just so you can use a cool new language.
Interestingly, I saw it happen almost everywhere. It looks like people are more likely to down-vote comments which are contradicted by a recognized authority. This is of course not a good thing.
> You aren't really an outsider considering your participation in the Haskell Cafe mailing list and being credited in Real World Haskell.
I didn't post more than a few messages, 2 years ago, and I posted about 3 minor comments in Real World Haskell. I've read a few papers, but seldom have written anything (except http://www.loup-vaillant.fr/articles/assignment of course). I'm not an outsider, but hardly what I consider to be an Insider.
> You also don't have any proof that most software is custom or private.
I don't. But in this (huge) niche, my point still stand: being afraid of the GPL is silly. Corporations that are should stop being.
> you cannot deny that the shrink-wrap industry is huge
I cannot and I won't.
> The answer is to avoid GPL code in the language […]
Yes, assuming you want the (proprietary) shrink-wrap industry to use Haskell. I want it gone. Therefore, I see the GPL as the solution.
That you cannot see this is because you also have the same bias as Dons.
Haskell may not be the perfect language for your generic FFT library to be distributed with your OS, but it's a great choice for building applications that would otherwise be C++ or Java. Java and C++ had no trouble catching on, despite being slower than C, and Haskell isn't even that much slower than C.
Haskell code that performs close (within an order of magnitude in terms of run time and space) to its C/C++ equivalent typically is also close in code length (and often less readable!) and often unsafe as well (requires explicit unboxing etc.)