I'm trying to learn Haskell (for fun, of course). My only previous experience with the functional programming paradigm was playing around with Scheme a bit. I was nodding my head to "A Gentle Introduction to Haskell" until I got to this, from section 2.2, User-Defined Types:
"Note that the type of the binary data constructor Pt is a -> a -> Point a, ..."
This is from http://www.haskell.org/tutorial/goodies.html
Now, where the heck does this type come from, and what does it mean? Just a paragraph before, we learn that "-> is a type constructor: given two types t and u, t->u is the type of functions mapping elements of type t to elements of type u."
So Pt maps elements of "a -> a" to elements of "Point a"? Or does it map elements of "a" to elements of "a -> Point a"? How does either of these possibilities make any sense? Seems like it maps two elements of type "a" to a single element of type "Point a", no?
I tried the "just ignore and keep reading, hoping it will make sense later" technique, but the next section, 2.2.1, Recursive Types, defines the Branch type in a similarly baffling way. Hopefully, someone more knowledgeable here will be so kind as to clear this up for me.
I know fuck all about Haskell, but that sounds vaguely like curried functions to me, which is the dumbest fucking idea to come out of functional programming ever.
I just posted this so I could bitch about curried function.
Thanks, that hint was enough to do it. I looked up "currying" on the wikipedia and now I'm beginning to understand. So in fact, the data type of Pt really is a -> (a -> Point a). And also, I don't have the necessary functional programming groundwork to read that tutorial. (But I will continue to try anyway.)
Perhaps you can enlighten me on why you believe curried functions to suck? It does not seem intrinsically obvious. What's more, Google returns no hits for "currying sucks" or "curried functions suck", so the rest of the Internet is no use in this matter.
I tried reading about currying a few weeks ago and my head imploded. That shit is weird. (But then, a lot of what falls under the "functional programming" heading seems weird to me: it just doesn't seem to fit my brain at all.)
I thought the wikipedia article was fairly easy to follow:
http://en.wikipedia.org/wiki/Currying
It's like, you want to have a function that takes two arguments, say, plus(2,4) = 6. But instead of doing it that way, you have plus(2) return a function that adds 2 to its argument, so you do (plus(2))(4) and that equals 6.
I guess you already have to be cool with the idea that functions can return functions. That was something I already understood from playing with Scheme. But other than that, currying seems a pretty straightforward concept.
What isn't straightforward is the pros and cons of currying in practice, which is why I'm interested in what >>2 has to say about the latter.
It's a retarded notation in my opinion, but it makes sense because of the way these languages don't take multiple arguments.
I usually just take a shortcut and interpret something like "a -> b -> c" as two arguments (a and b), and a result (c).
>>5
Take a look at http://haskell.org/hawiki/Currying
BTW, the "gentle introduction to Haskell" totally sucks. You should use Hal Daume's tutorial instead: http://www.isi.edu/~hdaume/htut/tutorial.pdf
> It's a retarded notation in my opinion, but it makes sense because of the way these languages don't take multiple arguments.
Well, that's just the thing, isn't it? Why are these languages arbitarily forbidding multiple arguments, and then going to great lengths to re-introduce them? You could argue that it's useful to be able to create functions that have several arguments set to static values, which is true, but currying sucks at this too, because you can't set arbitary arguments, you have to set them in a specific order. In the end, it's all incredibly lame academic wanking.
Actually, what it is, is an eruv. http://en.wikipedia.org/wiki/Eruv
Orthodox Judaism forbids a number of things on the shabbat. However, this is apparently far too inconvenient to actually follow, so what is done is that a wire is strung up around an entire neighbourhood, creating a "wall" that makes the whole neighbourhood a walled-in area, where these actions are allowed.
Basically, you create an arbitary limitations, and then you spend a whole lot of effort to get around your arbiatry self-imposed limitations without technically breaking it. I think it's retarded in religious dogma, and I think it's retarded in programming languages.
PS: Most modern functional/imperative hybrid scripting languages (Perl, Python, Javascript, and so on) can already do partial function evaluation in a much more generic and useful fashion. They could use some syntactic sugar for it, but it does work a lot better than currying.
It makes the semantics of the language much simpler for all functions to be equivalent; I think that's the real reason for it. You do have a point about not being able to partially evaluate in an arbitrary order, though.
Computer in this day and age are massively complex - why on earth would you want semantics to be simple to that extent?
No, I know, silly academic dogmatics.
Ah, a Perl programmer speaks.
>>11, but that is exactly why semantics should be simple. If the problem you're trying to solve is complex, why distract yourself by dealing with a big language as well?
Because I can solve a problem quicker if I don't have to fight the limitaitons of the language every step of the way?
For me, currying is nice because you can do things like map succ list
instead of map (\x -> succ x) list
. Or map (+1) list
as opposed to map (\x -> x+1) list
.
Simple constructions to build complex stuff versus complex constructions is just different philosophies in programming, I guess.
I don't see how the first example has anything to do with currying. Of course, I don't know the language, but I really don't see anything about that that couldn't be done just as well with syntactic sugar and no currying. For the second, are you currying infix operators? That seems questionable at best.
Overall, that's just the equivalent of syntactic sugar. Hardly a good argument for a fundamental construct.
And I realy disagree that you can dismiss things as "just" different philosophies. All philosophies are not born equal.
>>17
Well, the nice thing about it is that it doesn't need syntactic sugar for it to work (except for infix obviously).
A disadvantage with currying is that you can't have empty arguments or implied arguments or whatever they are called where you only have to enter the first argument and the second is implied. Haskell comes up with a contrived method to counter that.
As I said, most scripting languages can do that, without doing any currying. The syntax isn't as neat, but it does work a lot better than currying. In Javascript:
var partial=function(a,b) { some_function(1,a,2,b) }
partial(3,4);
Well, duh, C can do that. As can Haskell or pretty much anything else.
Yes, all the more reason to not bother with currying.
Of course, most of the scripting languages also do closures, so you can do:
var something=1,other=2;
var partial=function(a,b) { some_function(something,a,other,b) }
partial(3,4);
That doesn't need a closure.
/* C code */
int something=1, other=2;
void partial(int a, int b) {
some_function(something,a,other,b);
}
partial(3,4);
It does if you're changing the values of those variables.
That said, Javascripts closures act really strange. You often end up having to kludge them to make them work right.
>>24
Changing what variables?
There are only two variables in that example of yours, and I was referring to both of them.
Haskell doesn't forbid multiple arguments. It has two many ways to take multiple arguments. First is currying. The second is through tuples. Or you can make your own type like a tuple and have a function take that type.
(+) :: Int -> (Int -> Int)
This addition function takes an Int
which returns a function which takes an Int
which returns an Int
. I put the brackets in for illustration.
(+) :: (Int,Int) -> Int
This addition function takes a tuple of two Int
s and returns an Int
.
(+) :: (Pair Int Int) -> Int
This takes a type called Pair
which holds two Int
s and returns an Int
.
The second way is a lot like how C takes arguments. And Haskell can do what >>22 shows too, so currying is less a limitation than a feature or an integral part of the language because Haskell comes from typed lambda calculus.
I wasn't arguing against Haskell, just against currying. If Haskell can do all that, why does it bother with currying?
>>29
Your arguments were that it doesn't take multiple arguments and you can't set arbitrary arguments to static values. Haskell can take multiple arguments like I said in >>27. Haskell can do arbitrary arguments just like in >>20. Currying just forces setting the arguments in 1 order (but arbitrary is possible too like in >>20) which is convenient.
A tuple is a single argument.
I don't know about Haskell, but in Ocaml taking a tuple apart is hardly as nice as having variables handed to you directly. If you want to discuss syntactic ugliness to work around multiple arguments, this is it.