Hacker News new | past | comments | ask | show | jobs | submit login
An HTTP client in Haskell using io-streams (operationaldynamics.com)
41 points by dons on March 6, 2013 | hide | past | favorite | 16 comments



I have to say this looks like a really convenient library!

Aside: As a Haskell beginner, I find it astonishing that 1-letter names are the norm in Haskell-land. To me, names are not just placeholders imposed on you by the language, they should convey meaning, too!


As always, parametric polymorphism necessitates one-letter names, as variables can really stand for anything at all. The compiler guarantees you can't know much (or anything) about some polymorphic variables.

Other idioms come from math, e.g. 'x' for an unknown value, and then we get 'xs' for a list of unknown values.

    map :: (a -> b) -> [a] -> [b]
    map f (x:xs) = f x : map f xs
Is much clearer than the Zed Shaw version:

    map theFunction (firstElement:otherElements) = theFunction firstElement : map theFunction otherElements


I'm aware of polymorphism and the list convention and I'm not going to argue against them.

However, the example code uses `c' for connection and `q' for query. Surely, knowing what those are from the variable name would be a good thing?

It's not that I want to impose Obj-C's verbosity but the other extreme (1-letter names) is just as bad.


It's not often discussed in polite company, but Haskell programmers are actually not Homo sapiens sapiens. They're a whole other sentient species walking invisibly among us. Their Achilles heel is the keystroke: each one like smoking a cigarette is to us (in terms of damage, not addiction). So while you and I have the luxury of calling something "connection", a Haskell programmer considers that 9 steps closer to fingertip cancer.


> However, the example code uses `c' for connection and `q' for query. Surely, knowing what those are from the variable name would be a good thing?

In this case, the example is short enough that there's no chance of confusion (for the intended audience): clearly c is a connection and q is a request. They're only used in those few lines.

However, I wouldn't say 1-letter names are the norm in typical Haskell code (outside type variables).


In the end it's a matter of taste, I find the second version much clearer


I think they are both caricatural.

I don't write haskell but if I did I think I'd go with:

    map func (first:rest) = func first : map func rest
Maybe using car and cdr for first and rest because of my lisp background.

That being said, for such a simple function using f, x and xs is probably fine (the way using int i; in C is fine).


The first version is pretty standard Haskell. Certainly not caricatural.

For generic code, writing first:rest is not bad but it does look a bit superfluous, somewhat like writing

    quotient = numerator / denominator 
instead of simply x = y / z. It doesn't really give you any extra information, and for me it sort of suggests that the programmer needs to remind themselves of what the operators : and / mean.

Of course, if the code is not generic and the variables do have concrete meanings you should name them appropriately, e.g. roi = return / investment. But when we write x:xs it's typically polymorphic (or otherwise generic) code.


It's quite common in Haskell to give 1-letter names to variables that are short lived.

Also, Haskell programmers use 1-letter variable names in functions that could/should be made point free [1] but aren't for some reason [2].

[1] \c -> c + 1 is not point free whereas (+1) is. An expression is point free if it doesn't have any bound variable.

[2] Because reasoning with flip or const may be confusing in the current context for example.


They should and they do. But for local variables Haskell programmers generally assert one letter adequately conveys the meaning, especially since you know the type. But the second you can't is also the second you should use more than one letter.


They're conventions that work because you see them over and over in small functions, the "small functions" being key.

    (go), type parameters, (x:xs) "\ds ->", "import qualified This as That".
I think it's just like a java programmer internalizes when to use HashSet, HashMap, TreeSet, ArrayList etc. After a while you just know what to do.

______________

yesterday's long debate about this:

http://www.reddit.com/r/programming/comments/19mw7v/on_f_rea...

________

APL and C, with some scheme and prolog thrown in, were my first languages, so maybe readability just isn't important to me ;-}


Well, at least the monad abuse uses a real monad, but why not just use lens (http://lens.github.com/)?


Io-streams looks nice, but I think I'll stay with pipes. Along with pipes-safe, it lets you for instance open resources safely inside your stream, which is a very convenient feature at times.


I like Snap, but I am still skeptic too. One of the nicer things of enumeratee, conduit, and pipes is that you can use them in pure code as well. io-streams drags in the IO monad if you want to structure code as streams, even if your 'enumerator', 'enumeratee' or 'iterator' is pure.


I think that's a design goal. The idea is to pipe IO streams and not arbitrary streams, which seems to make for a much less complicated machinery (just look at the types signatures from pipes :) ). It's a viable design choice, but it certainly has drawbacks as well.


Look Ma, no sockets?)




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: