On Haskell, Ruby, and Cards Against Humanity
drmaciver.com
drmaciver.com
The fallacy here is that type classes, folds and monads are not esoteric structures within the context of Haskell, and using them to structure regular business is pretty mundane. If someone feels a sense of achievement from doing this, they're probably very new to the language. The author of the article has baked in a value judgement about the "normal" way to structure a CRUD application that precludes alternative approaches to structuring application logic.
You could just as well argue that laying out object class hierarchies and using inheritance is "[solving problems] that have nothing to do with what you’re actually trying to achieve."
Definitely, 100%.
Could, indeed semi-regularly do. I actively dislike solving problems with inheritance.
I also actively dislike people missing the point. The problem is not "using programming to solve problems". The problem is letting the novelty of the programming you're using to solve problems con you into thinking you're doing something more clever than you actually are.
If we're talking about things that make me smug as a Haskell developer, I'd probably say that I feel most accomplished when I figure out how to encode more invariants into the type system so that the compiler helps me make fewer errors. I still stand by Haskell as being the best language for that that's not just a university research language.
Missingthepointception!
It's almost like I didn't explicitly point to this as a phase most serious Haskell programmers grow out of right in the goddamn article.
Another way of putting this doesn't have anything to do with how clever the developer thinks they are (or how serious they are now that they no longer think they're clever)...
It's "now you have two problems" -- the original problem you wanted to solve, and the problem of working with the tool/framework/paradigm you've chosen to solve it. So, great, you're doing object/design-pattern oriented development! And then you find this starts to lead you to a place where a significant portion of your overhead is sunk into solving problems that don't seem to have much to do with the original problem domain.
I don't know Haskell well enough to pick on it. I'd love to believe it escapes that kind of problem, but I think it's only somewhat less likely than beating entropy.
Which people? My friends and I walk away from a game of Cards Against Humanity thinking we had a fun time coming up with stupid combinations for an hour. I can also turn the author's previous sentence around and state that there are probably many people that get too invested in elves and orcs as well.
> ... this passes once you’re more familiar with the language and are using it for real things
> ... a large enough subset of the community never reaches that stage
This is true about pretty much every programming language (and probably generalizable to most non-programming things too). The author just happened to apply it to Ruby and Haskell for some reason.
If there's a message such as "programmers should be more aware of the language's strengths and weaknesses and shouldn't feel overconfident", it's lost in the paragraphs of vague complaints.
After playing a game of CAH, I don't think any of my friends have any delusions about doing standup or writing a comedic op-ed piece for the NY Times.
And so you begin to shoehorn absolutely everything into the new magic potion you've learned. Erlang? How can I build concurrent and robust systems with it, it's dynamically typed and the syntax is scary! (Yes, people who somehow managed to learn Haskell syntax proceed to cry like babies over having to figure out some clause delimiters. The irony is enough to power the US steel industry for a year.) Mutable state and its evil becomes the next cargo cult, type systems means I no longer have to test my software, and other similar misconceptions abound.
But, I don't mind. Most tend to grow out of it eventually. You feel hardcore at first, but you're struck by humility once you learn more and more.
By the way, Cards Against Humanity is quite nice.
Right. I think, in general, PFP (pure-FP, i.e. Haskell and a few more obscure languages) sells itself as a solution to a problem and some people start believing it's the only solution to the problem, rather than one of many (and probably not the best one, at that). Not that Haskell's virtues aren't real -- they are -- but they come at significant cost, and are often available come much cheaper with other approaches. For example, referential-transparency-everywhere is just one of several solutions to the problem of mutable shared state, and, IMO at least, not among the best solutions. Even when it comes to provable correctness, which Haskell touts as a relatively unique feature (at least relative to mainstream languages) people forget -- or more likely, don't know -- that there are fully verifiable imperative languages out there (with their own serious problems -- correctness is never free), that have actually been used by the industry to write some very important, safety-critical software, and have been actually put to the test much more than Haskell.
In fact, one of Haskell's marketing advantages is that, after 20 years, it is still at the stage of selling the dream. Because it has hardly been used where its strengths are supposed to matter most (complex programs employing a lot of concurrency), it gets to sell its "promising initial results" without having to contend with too much disappointment, which invariably arrives once a technology has been well tested. It's the promising NBA rookie who got picked first in the draft but has never played a full quarter, getting people to say, "if only they'd get him off the bench...".
Ada is absolutely painful to work with as a developer (I used to work in Aerospace). But if you could get your code to compile, it stood a very good chance of just working.
Anyway, lots of the reported production uses of Haskell are in exactly the areas it is supposed to be strong; the problem for sharing that experience is many of them are in internal proprietary systems, not publicly-available or open-source software, so external evaluators don't have the code -- or even, often, a chance to interact with the software.
Well, this isn't a very technical discussion, but I can quickly list them: for shared mutation I think the Clojure approach of transactional/atomic mutation everywhere rather than RT-everywhere is simpler; for correctness/side-effects, imperative effect systems may be easier (well, they don't quite exist other than in a very limited, experimental form, in Koka and Java 8's pluggable type systems -- but Haskell doesn't provide a very fine-grained side-effect-control either). For correctness, Esterel (which has been well proven) and its descendants, seems a lot more sophisticated in terms of proving correctness, while being more intuitive (of course, Esterel introduces a limited computation model, but so does Haskell -- or languages in the same vain -- if they are to be decidable).
> the problem for sharing that experience is many of them are in internal proprietary systems
Yes, that, too, is a problem, but the bigger problem is that uses in the industry are vanishingly rare -- and the bigger the domain challenge, the rarer still they are. For example, I don't think there exists a single case of a Haskell program that tackles complexity in such a way that implementing it in, say, Java or Clojure, is prohibitively expensive.
Among the companies listed are Facebook and Microsoft.
This list may not be long or exhaustive but it does show a number of companies who are publicly willing to say they use Haskell. It was started in January.
I can personally attest to several companies I have worked with not mentioned in the list which also use Haskell internally. Haskell is not always the bread and butter of the business software. However, it often has an extremely strong presence for developing internal tools, compilers for DSL's, and (micro)services for various tasks.
I wouldn't go there. Awk has an extremely strong presence in internal tools; Haskell has some minor presence if you squint hard enough. If the unconventional language promising to help tackle software complexity in this modern age is used as an Awk replacement (or TCL, or Perl) then what are we doing here?
The real story is that Haskell may well be an excellent first step towards the future of programming and a great breakthrough -- or it may be a dead end -- we simply don't know because it's never really been tried. Putting it in the ring with Awk or Perl -- where it's losing, BTW -- is an insult to both Haskell and Awk. Using Haskell as one more language for "small stuff" is not using it at all, because that's not what it's meant to do, and it's certainly not where it can fulfill its promise.
I think playing around with the abstractions that Haskell offers can be very rewarding when you go back to your "regular language". It's just approachable enough that you can learn some really advanced techniques and dip your toes into category theory all through self study.
As for Ruby, I'm not proficient in it, but plenty of people have built amazing products using it and seem happy with their language of choice. Not sure why they should be bashed for poor programming when in the end, results are the only thing that matters.
> A thing I value probably at least as much as humour is good API design.
Since he's throwing a lot of rocks, I'll say his house is looking pretty glass :) Slaying imaginary orcs isn't exactly the height of comedy.
Never say that, or I will burn the building down.
I'd be a lot more interested in hearing why the author thinks the Sequel and Sinatra APIs are good, and how they differ from more typical poor Ruby APIs, and what features of Ruby the author thinks encourages these poor APIs.
What languages or language communities encourage better practices, and what makes them different from Haskell and Ruby, and how does that tie back to the Cards Against Humanity analogy? By the end of the piece, I was left wondering what the point was to begin with.
No that's not what the video demonstrates because the people in the video are professionals.
Ironically the whole monkey-see-man-do-therefore-monkey-can-do-too argument that you're espousing with the 'professional status notwithstanding' line is itself demonstrating one of the actual points of the article, namely the 'I saw someone do this on jackass once so I should be ok to hurl myself out of this window while on fire and with my junk in a snapping-turtle' idea.
Actually, it's a game about having fun with crude humor.
The video demonstrates that it's just a game that generates laughs and eases people's insecurities therefore making them more open to come up with their own humor or be more receptive to others'. I mean, just look at Laina's reactions throughout the video, she clearly represents the type of person that is obviously uncomfortable but being drawn out of their shell.
The point is that the game itself is not the point, it's the setting. Your ridiculous Jackass strawman has no bearing.
main = putStrLn $ unlines $ map fizzer [1..100] where
fizzer n | n % 15 == 0 = "FizzBuzz"
| n % 3 == 0 = "Fizz"
| n % 5 == 0 = "Buzz"
| otherwise = show n
but I think the first time I tried to solve it in Haskell I had something more like: import Data.Monoid (Monoid, mconcat)
import Data.Maybe (catMaybes)
specialcases :: (Monoid y) => [x -> Maybe y] -> x -> Either x y
specialcases rules x = case catMaybes (map ($ x) rules) of
[] -> Left x
xs -> Right (mconcat xs)
ifDivBy :: Integer -> x -> Integer -> Maybe x
ifDivBy n x m = if m `mod` n == 0 then Just x
else Nothing
main = putStrLn $ unlines $ strings where
strings = map (either show id) cases
fizzer = specialcases [ifDivBy 3 "Fizz", ifDivBy 5 "Buzz"]
cases = map fizzer [1..100]
This is basically thinking about an imperative problem the "wrong way around": starting with the logical distinction between "we're in a special case" and "we're in the normal case" and building everything else around it. (Also, who is ever going to use that Monoid instance? Replace `id` with `concat` and you can just remove `Data.Monoid` altogether -- and if you really wanted it generic, taking an explicit `y -> y -> y` and using `foldl1` would be more flexible anyway.)[0] consider that 50% of people are less funny than average, and then reflect on how funny the average person is.
You cannot meaningfully add together how funny five people are and divide it by five. However, you can put five people in order of how funny they are, and point to the middle one.
The only appropriate concept of average for ordinal data (e.g. how funny someone is) is the median, from which it follows by definition that 50% of people are less funny than average.
PS - if it is true that it "cracks you up" every time you hear "the 50% of people are above/below average fallacy", I suggest that you might be one of the 50% of people who have a below-average sense of humour ;)
I would extrapolate further and say since there is a tiny number of comedians performing any night that there is both a non-even distribution of humor and that it is weighted towards fewer people having it. Consider, if it were so common, would the rest of us be as willing to pay to hear someone else perform?
And to be fair, I don't think that would be evidence in itself. I would be curious to see actual studies into this. At least a little.
Incorrect. For the four usual kinds of measures, the following types of "averages" are generally useful:
Nominal: Mode
Ordinal: Mode, Median
Interval: Mode, Median, Arithmetic Mean
Ratio: Mode, Median, All Means (arithmetic, geometric, harmonic)
> from which it follows by definition that 50% of people are less funny than average.
Nope, that only follows by definition for ordinal data with the additional assumption that no items have equal rank.
Assuming that average here is an arithmetic mean (which is the most common use, but how are we quantifying "funniness" to warrant such a measure?), this would only be true if we assume a symmetric distribution with no individuals at the average.
This also assumes that objective funniness is even a meaningful concept; funniness is obviously subjective, and I would suspect that people tend to voluntarily socially engage with people that they find pleasant to be around -- part of which is having compatible sense of humor. So, the people you are voluntarily associating with (i.e., the people you are like to play CAH with) are likely to be disproportionately from the upper end of the funniness distribution from your subjective perspective -- and are likely to be among the upper end of the distribution in how they perceive your funniness, as well.
Your second point is a good one - clearly, funniness is subjective. On the other hand, I don't think my argument relies on the precise quantitative definition of funniness!
Most DSLs (at least the ones I've worked with, or made), are simply a convenience, and eventually to make the code more expressive.
Behind this fancy DSL, there is an API, the DSL itself isn't really an API, it's just a "frontend" for that API.
I'll pull a simple and shitty example out of my ass[1]:
game = Game::CardsAgainstHumanity.new do
fun 9000
rounds 10
must_involve_drinking!
end
which could be a DSL for doing something like: game = Game::CardsAgainstHumanity.new()
game.configuration(:fun_level, 9000)
game.configuration(:round_count, 10)
game.set_game_flag(:drinking, true)
game.set_game_flag(:drinking_optional, false)
Like I said, this is a shit example. The API behind this could be way more complex and allow for much greater fine-tuning of stuff than the DSL would, but the DSL exist for stuff that's common.Also, one would have to go out of their way to hide the actual API behind the DSL, which is very unlikely and due to Ruby's nature, one could always expose the API anyway (through the C API, as a last resort).
Also, I'd like to add little bit of something about the Haskell part, even though I've never written one line of Haskell, but this isn't really about Haskell:
> "Look, I used a monad! And defined my own type class for custom folding of data! Isn’t that amazing?“. “What does it do?” “It’s a CRUD app”
I bet everyone did the same or something of that sort in <pick your language> when they were starting out with it, or exploring some part of it that they were previously unfamiliar with. This is excellent, actually. Why? Because they'll learn the benefits and pitfalls of that approach. They'll be wiser and better programmers tomorrow because of that.
--- [1]: No pun intended. Also, not looking for a real example out of principle, because I feel like the author was too lazy to do some research; this is just my opinion. Frankly, this feels like click-baiting.
For instance most API design is based off the standard Rails scaffold command, and an explanation about what's wrong about that would have been nice, and elevated this article from kind of a screed, into something informative and worthy of study.
I don't know Haskell but I've started trying to learn it a couple times. Haskell is close to how I think about problems, not sure how close yet, but I can tell it would be a great tool if I took the time to learn it. I'd probably learn a lot about how to think about problems if I did use it, and that's probably what happens for other people. It's such a major paradigm shift from the 'usual' methods that it's raised to an exalted status. If you try to solve problems without using state and with static types you can get to almost the same place regardless of language, it's just harder to implement. I've been working in Java 6 with a team firmly rooted in OO the last few years and often wish I had monads...
There it is, in the last paragraph. I was wondering what you are trying to say. But I guarantee you, it's not Ruby or Haskell making them like that. It's rather something intrinsic that feeds on accomplishment, however little it might seem to you. On the other hand, there's also a lot of mathematicians, bloggers and even roleplayers who display quite similar behavior.
Just imagine the pride of the young mathematicians when they prove something difficult for the first time without the help of a text book, when the professor could solve this in his sleep. Or think of the blogger that spreads the word on his latest article, when a philosopher or writer thinks it doesn't say much about anything. Or the roleplayer boasting about his skill for acting out his character, when an actual actor thinks its laughable.
Many people, irrespective of what they're doing, display this kind of behavior. So if these people annoy you so much, avoid them or help them.
Don't tell them that it's frustrating to interact with them. I guess you wouldn't have enjoyed it either if you just started out and someone would have told you that all your accomplishments until now are worth nothing and you shouldn't tell or show anybody what you are doing since it's embarrassing for the community.
Nobody is good at everything, I know a thousand things that I don't know or which I would execute terribly. But I know that I can still reduce this number. And if it takes me a whole week to write a program that is an abomination and it would've been a matter of hours for you, I'll still tell it to everybody since I'm proud of however little it is that I can accomplish.
On the other hand, I won't laugh at you and I won't tell you that it's frustrating to talk to you if you say something about the LHC or black holes or semiconductor physics when you barely have an idea about quantum field theory, general relativity and solid state phyiscs. I'll either avoid you or - what is usually the case - I'll help you understand it.
(Yes, I like Ruby, I like to poke Haskell occasionally, and I've only played Cards Against Humanity once, but it resulted in my mother-in-law combining "a girl's best friend" and "three dicks at once".)
Is there a a difficulty barrier for considering an application real? A lines of code requirement? Is it like pornography and I'll know it when I see it?
I'd rather surround myself with people who are generally happy about things -- those who laugh a lot when playing games like Cards Against Humanity and celebrate achievements, even if they're small -- than those who spend their time writing angry rants about how they're so much funnier and better at programming than everyone else.
Maybe the OP tried to make a more important point somewhere in the article, but it was surely lost to me among the rant.
Wow. There's a lot going on there, up in that ivory tower.
Got it.
Holy non-sequitur, Batman.
Why would that be an obvious reason to hate it: its not like middle-class white kids are the only people who play Cards Against Humanity. (The few times I've played it, the only one of those descriptors that was accurate of the group as a whole was "middle-class" -- the groups were racially diverse and included an age range of something like mid-20s to early 50s.)
> What I really hate about it is that it’s a game about convincing yourself that you’re much funnier than you actually are.
Er, no. The whole thing is about creative juxtaposition from limited options. Its not really about how funny you are, its about how funny things taken in the wrong context can be. Like Mad Libs, its about how funny the result is, and while there is definitely more deliberate input from the participants, its not mostly about how funny the participants are, because the participants are so sharply constrained that even if they were the world's greatest comedian, they wouldn't be able to show it.
> People walk away from a game of Cards Against Humanity thinking that they’re hilarious.
Yeah, I don't see any evidence that this is particularly true.
And the thing is, that the amount that the author here doesn't get CAH is echoed in the amount he doesn't see to get the things he uses it as an analogy for.
> There are some exceptions (Sequel and Sinatra for example), but by and large Ruby APIs seem almost actively designed to promote bad software.
Its interesting that the author can name notable counter-examples to the effect he is describing, but can't be bothered to name even a single notable supporting example.
Sure, lots of stuff written in Ruby or any language is bad. But where is the evidence that Ruby disproportionately (either inherently or through community dynamics) promotes bad design? There's no substance here.
> Ruby is full of people who think they’re doing good API design, but they’re not. The problem is that in Ruby everyone is designing “DSLs”.
That's not even a coherent complaint. There is essentially no difference between an internal DSL and an API.
> The focus is on making the examples look pretty.
I don't see a lot of evidence that this is true.
> I’m all for making examples look pretty, but when you focus on that to the exclusion of the underlying semantics, what you get is the Cards Against Humanity effect all over again. You’re not doing good API design – you’re doing something that has the appearance of good API design, but is in reality horrifically non-modular and will break in catastrophic ways the first time something unexpected happens, but the lovely syntax lets you pat yourself on the back and tell yourself what a good API designer you are.
That's a nice generality, but where is the evidence or argument supporting the idea that this is somehow more common of a problem in Ruby than other languages?
> The way this problem manifests in Haskell is in how incredibly clever it makes you feel to get something done in it.
I don't feel particularly clever getting something done in Haskell. I occasionally am amazed at how succinct the solution is compared to what it would be in some other language, or how in solving a particular problem I've also created something that could be reused that would solve a more general class of problems, or how I didn't have to use boilerplate template code with fill-in-the-blanks to solve a particular case of well-known general problem as I would in many other languages, but was instead able to leverage an existing more general solution because of Haskell's more powerful abstractions.
But that's more about thinking that the designers of the Haskell library and language were clever than that I was. And its part of the process of learning new languages/libraries that have different strengths than those you are familiar with. I remember doing similar things (different details, of course) with pretty much every language other than my first.