Haskell confusion (81)

1 Name: #!usr/bin/anon 2005-11-05 03:09 ID:B+nCC/mJ

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.

2 Name: !WAHa.06x36 2005-11-05 03:26 ID:Heaven

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.

3 Name: #!usr/bin/anon 2005-11-05 04:21 ID:B+nCC/mJ

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.

4 Name: #!usr/bin/anon 2005-11-05 04:48 ID:OHdwZ41d

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.)

5 Name: 1,3 2005-11-05 05:03 ID:B+nCC/mJ

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.

6 Name: dmpk2k!hinhT6kz2E 2005-11-05 05:07 ID:Heaven

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).

7 Name: reppie 2005-11-05 11:00 ID:kJQGh5ky

>>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

8 Name: !WAHa.06x36 2005-11-05 14:19 ID:S3bCbd+J

> 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.

9 Name: !WAHa.06x36 2005-11-05 14:47 ID:Heaven

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.

10 Name: #!usr/bin/anon 2005-11-05 16:17 ID:B+nCC/mJ

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.

11 Name: !WAHa.06x36 2005-11-05 18:54 ID:Heaven

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.

12 Name: #!usr/bin/anon 2005-11-05 22:12 ID:Heaven

Ah, a Perl programmer speaks.

13 Name: #!usr/bin/anon 2005-11-05 23:19 ID:B+nCC/mJ

>>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?

14 Name: !WAHa.06x36 2005-11-06 01:36 ID:Heaven

>>13

Because I can solve a problem quicker if I don't have to fight the limitaitons of the language every step of the way?

15 Name: #!usr/bin/anon 2005-11-06 02:03 ID:OHdwZ41d

>>13
It's the difference between simple (easy to use) and simple (unable to express complex ideas);

>>8
>>14
Amen.

16 Name: #!usr/bin/anon 2005-11-08 18:15 ID:MM8a1853

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.

17 Name: !WAHa.06x36 2005-11-08 19:18 ID:Heaven

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.

18 Name: #!usr/bin/anon 2005-11-09 23:41 ID:Heaven

>>17
Yes, >>16 is currying infix operators. When that is done, it is called a "section."

19 Name: #!usr/bin/anon 2005-11-11 02:43 ID:P/Wff3Bl

>>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.

20 Name: !WAHa.06x36 2005-11-11 13:03 ID:pwaUKK3K

>>19

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);

21 Name: #!usr/bin/anon 2005-11-11 17:55 ID:Heaven

Well, duh, C can do that. As can Haskell or pretty much anything else.

22 Name: !WAHa.06x36 2005-11-11 18:12 ID:Heaven

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);

23 Name: #!usr/bin/anon 2005-11-11 22:40 ID:Heaven

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);

24 Name: !WAHa.06x36 2005-11-11 23:05 ID:Heaven

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.

25 Name: #!usr/bin/anon 2005-11-12 00:18 ID:Heaven

>>24
Changing what variables?

26 Name: !WAHa.06x36 2005-11-13 03:06 ID:Heaven

>>25

There are only two variables in that example of yours, and I was referring to both of them.

27 Name: #!usr/bin/anon 2005-11-15 23:53 ID:P/Wff3Bl

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 Ints and returns an Int.

(+) :: (Pair Int Int) -> Int
This takes a type called Pair which holds two Ints 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.

28 Name: #!usr/bin/anon 2005-11-15 23:54 ID:P/Wff3Bl

>>27
s/22/20/

29 Name: !WAHa.06x36 2005-11-16 01:39 ID:S3bCbd+J

>>27

I wasn't arguing against Haskell, just against currying. If Haskell can do all that, why does it bother with currying?

30 Name: #!usr/bin/anon 2005-11-16 04:27 ID:P/Wff3Bl

>>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.

31 Name: dmpk2k!hinhT6kz2E 2005-11-16 06:52 ID:Heaven

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.

32 Name: !WAHa.06x36 2005-11-16 12:44 ID:pwaUKK3K

>>30

Again, I was arguing about functional languages in general and the idea that taking multiple arguments is somehow bad, not Haskell in particular.

But let's talk about Haskell: As you say, you have not one but two different methods now to work around the one-argument-per-function limitation, currying and passing tuples. Why would you still want to hang on to the single-argument dogma? It's already created extra complexity and confusion by introducing multiple workarounds, instead of a single, well-defined method for taking multiple arguments.

33 Name: #!usr/bin/anon 2005-11-17 04:25 ID:Heaven

It's convenient in many practical situations. End of story.

34 Name: #!usr/bin/anon 2005-11-17 11:57 ID:Heaven

Wait, there are practical situations in which one uses Haskell?

35 Name: !WAHa.06x36 2005-11-17 12:52 ID:Heaven

>>33

Then why not implement syntactic sugar for a system that is more convenient, and doesn't have the limitaiton of only letting you partially evaluate only the final arguments?

36 Name: #!usr/bin/anon 2005-11-18 17:58 ID:Heaven

Um. There is a system that doesn't have that limitation. It's called tuples.

C has the ++ operator. It's limited, but convenient. When it doesn't suffice, you use += or +. Same idea, no?

37 Name: !WAHa.06x36 2005-11-18 19:46 ID:Heaven

Well, that just reduces currying to syntactic sugar, again. I'm quite sure any number of computer scientists and language designers would disagree with classifying it as that.

38 Name: #!usr/bin/anon 2005-11-18 23:10 ID:Heaven

That's nice. I'm glad you have so much fun arguing with strawmen of your own invention.

39 Name: #!/usr/bin/anon 2006-01-31 17:24 ID:B+nCC/mJ

age!

I'm >>1 and I'm still learning Haskell, just figured out monads the other day. This is pretty cool stuff.

40 Name: #!/usr/bin/anonymous : 2006-03-28 10:22 ID:zOHco2oP

>>37
Haven't you learned anything? Syntactic sugar is good. Say that a couple of times. Or would you rather index your C array with *(base + index)? Verbose syntax, as we've seen with Javur, is the very enemy of refactoring. And you aren't going to chisel your code onto slabs of marble the first time around. "The program is complete, now it only needs to be compiled."

Non-PITA partial application is the very reason that you can define things such as the following:
sum = foldr (+) 0
It follows, then, that
concat = foldr (++) []
Do that in LISP and choke on your tens of lambda expressions and lack of static typing a couple of years on when something unexpected comes along.

... also there's functions like 'flip', which is effectively (\f a b -> f b a). Though you are correct in that more useful orderings of parameters do come along. IMO that just goes to show that functional programming doesn't let you skip careful design either.

>>39
No you haven't. Monadic I/O maybe. That's not exactly hard, once you come to terms with tail recursion :-)

For the real ultimate power, read a good monad tutorial (Monads for the working haskell programmer, I think it's called), take two aspirin and prepare for a great big mindfuck. And another when you look up what a monad is in category theory (optional).

41 Name: !WAHa.06x36 : 2006-03-28 12:23 ID:SS6VpCbA

>>40

I'm a Perl programmer. I don't think you'll find me arguing against syntactic sugar. I was merely arguing that currying is not the quite all it's cracked up to be, and in practice is just an insufficiently convenient form of syntactic sugar. Note >>35.

42 Name: #!/usr/bin/anonymous : 2006-03-28 23:54 ID:Heaven

>>40
Yes I have. It is interesting that you claim to know what anonymous strangers on the internet have or have not figured out.

43 Name: #!/usr/bin/anonymous : 2006-03-29 16:13 ID:Heaven

>>42
Heh. Sorry about that. I'm used to a far lesser breed of people who hang out on programming boards. The "what's the printf command in C++ do???" kind. So I kind of assumed that like a true Internet hero, you'd read the IO monad part of the so-called "gentle introduction", grabbed a tight hold of "a two parts hubris, two parts misunderstanding and one part knowledge" and ran to where your parents wouldn't hear.

Mea culpa.

>>41
(Oh, friction between Haskell and Perl people. Who'da thunk it!) Certainly curried functions aren't without their issues, yet their immediate benefits in "real world code" as I've seen are so significant as to make me wonder if your distaste was really rooted somewhere else than mostly effortless partial application. Which is kind of odd, seeing as Perl is the vaguely C-like language where parentheses around function parameters are explicitly optional. I dare you however to present me with a day-to-day programming langage construct that was not without issues.

44 Name: !WAHa.06x36 : 2006-03-30 15:28 ID:SS6VpCbA

>>43

My main point is this: Curried functions were introduced because functional programmers somehow got into their heads that functions only take a single argument. Since nobody can write code that way, a workaround was needed, which is curried functions. The fact that you can make partially applied functions with it is a side-effect, and not the original purpose. It is, however, the only useful aspect of curried functions. So far, so good, but since this was not initially introduced as a way to partially evaluate functions, it's not very good at doing that.

What I'm saying is: Drop the idiocy of having functions that only take one argument, and also drop curried functions, and instead introduce a proper method to make paritally-applied functions that can actually apply any argument, and not just the last ones. Currying is just a workaround for a self-imposed limitation.

45 Name: #!/usr/bin/anonymous : 2006-03-31 04:47 ID:mdP3ZjKE

>>44

You're full of shit. Currying is one of the best things about haskell. It's all through the type-system, and it's used all through the standard library and common idioms of the language.

As for the 'single argument' thing, you can always make a function take a tuple of args. The only thing this succeeds in doing is making your code less flexible and annoying, so no one does it.

46 Name: dmpk2k!hinhT6kz2E : 2006-03-31 11:19 ID:Heaven

ITT we get along.

> Currying is one of the best things about haskell.

Currying struck me as something of interest mainly to mathematicians. I can't see how it would make Haskell great, or any other functional language for that matter.

Could you elaborate?

47 Name: #!/usr/bin/anonymous : 2006-03-31 15:15 ID:jLQEuxPf

>>46
It allows you to create partially-evaluated functions very, very easily, which comes in quite useful. You really need to try it before you'll get it, though. Lots of Haskell probably seems silly and useless from a distance.

48 Name: !WAHa.06x36 : 2006-03-31 18:56 ID:fwONFEhQ

>>45

You pretty obviously didn't read what I was actually saying, and neither do you seem to be aware of the theoretical background that the concept of currying comes from. Also:

> As for the 'single argument' thing, you can always make a function take a tuple of args. The only thing this succeeds in doing is making your code less flexible and annoying, so no one does it.

This is very much part of my argument.

49 Name: #!/usr/bin/anonymous : 2006-04-01 02:07 ID:Heaven

Who gives a shit about the theoretical background? Currying's useful.

50 Name: dmpk2k!hinhT6kz2E : 2006-04-01 02:46 ID:Heaven

>>47
I have tried currying, in Ocaml mind you, but I can't say I found any use for it.

Partial evaluation is handy, because I can pass around a single partially-evaluated function rather than all the arguments it took. I have difficulty seeing how passing around a function that took a single argument is helpful though. If you're going to do that, why not just pass around the argument in question instead?

Someone will have to explain this to me. :'(

51 Name: !WAHa.06x36 : 2006-04-01 14:56 ID:Heaven

>>49

Not useful ENOUGH. Because you can only partially evaluate the last arguments. From a practical viewpoint, this is a completely arbitary and meaningless restriction. From a theoretical viewpoint, it's a direct consequence of currying not being a method for partially evaluating functions in the first place.

In the end, it's half-assed.

52 Name: #!/usr/bin/anonymous : 2006-04-01 15:07 ID:Heaven

a half-assed tool for a half-assed job, i guess.

53 Name: #!/usr/bin/anonymous : 2006-04-01 16:19 ID:jLQEuxPf

>>51
That's why there's flip (flip f x y = f y x). Speaking of which, see what a nice definition that is? And flip foo does exactly what you expect.

If you have a function with four parameters and you want to fill in the third one, you could resort to a lambda, or write your own combinator like flip, but I don't see why that comes up enough to be a big deal. It's an issue of design: you put the most general parameters first.

54 Name: !WAHa.06x36 : 2006-04-02 14:04 ID:Heaven

>>53

So why not make a decent method for partial evaluation right from the start, instead of having several different ones, and various kludges?

(Answer, once again: Because currying isn't a method for partial evaluation, it's theoretical CS wanking. It's not meant to be useful, that's just a side effect.)

55 Name: #!/usr/bin/anonymous : 2006-04-02 14:38 ID:Heaven

Once again, have fun talking to yourself, !WAHa.06x36.

56 Name: !WAHa.06x36 : 2006-04-02 21:18 ID:Heaven

>>55

what

This thread has been closed. You cannot post in this thread any longer.