Hacker News new | ask | show | jobs
by trealira 761 days ago
I'm confused why it's said to be backwards (in the article and by you).

This paragraph shows that with a format string with an int format specifer, and then a string format specifier, the token list shows is exactly that, and the type it returns is a function that takes an Int and a String as input and returns a new string.

> For example, if the format string was "%d %s", the tokenization would be [IntFormat, NormalChar ' ', StrFormat], so the resulting type would be Int -> String -> String`. This might be confusing because it's a post-order traversal of the list, and might feel kind of backwards.

Isn't that exactly the order you'd expect?

I'm confused why it's called backwards, and why they say "post-order" traversal of a list, since I'm only used to hearing about traversing trees that way.

2 comments

Author here. It's a linked list, which is a tree, so post-order here means "recurse, then operate on the result" as opposed to "operate on something and then recurse on the result." So `f(head, r(tail))` instead of `r(f(head, tail))`. This post-order-ness can make it appear strange because first we go to the end of the list and produce the type String, then we process the second-to-last to get, say, the type Int->String, and so on until the first element, adding something to the front each time instead of to the back. The final result still has the parameters listed in the right order, as you mentioned, it's just that the order of operations to get there feels weird, where we're prepending to the return type instead of appending to the first parameter type. Sorry that was poorly written!
I see, now I understand. Thanks for elaborating!
I'm not that familiar with syntax of functional programming languages.

Isn't Int -> String -> String a shorthand for Int -> (String -> String)?

Thus I would have assumed the first argument to the result of sprintf "%s %d" would be an integer, then a string and the final result would be a string.

But the invocation would be sprintf "%s %d" "hello" 42, wouldn't it?

> Isn't Int -> String -> String a shorthand for Int -> (String -> String)?

Yes. Though I find it more convenient think of it as a function with multiple arguments and not a function that returns another function.

> Thus I would have assumed the first argument to the result of sprintf "%s %d" would be an integer, then a string and the final result would be a string.

Why assume that? (Not rhetorical.) Wouldn't that be like if in C, you had to write the arguments in reverse order of the format string, like this?

  printf("%s %d!\n", 5, "hi");
I seem to be missing something, thus thank you for taking your time

> Wouldn't that be like if in C, you had to write the arguments in reverse order of the format string, like this?

Exactly and that's not what we want

Let's go through this step by step:

sprintf "%s %d" returns a function, taking a string and returning a function taking an integer and returning a string, right?

sprintf "%s %d" "hello" returns a function taking an integer, returning a string, right?

sprintf "%s %d" "hello" 42 returns a string, right?

Thus my intuition of the return type of sprintf "%s %d" would be string -> (int -> string) not int -> (string -> string)

Your intuition is correct. I think you accidentally swapped %s and %d in one of your previous posts, leading to the confusion.

The "backwards" in the article is referring to the way the list is processed by the recursive function. The list and the resulting type are in the correct/intuitive order. I also found this sentence confusing.

By the way, thinking of a function of type a->b->c as a->(b->c) is technically correct and useful in certain cases, for example, when you are currying. But in most cases you can just read this as a function taking two arguments of types a and b, returning something of type c.