KallDrexx
KallDrexx

Reputation: 27803

Why does List.append prepend instead of append

I feel like I am misunderstanding something here.

Lets say I have the numbers 1, 2, 3, and 4 and I want to add 5 and 6 to it. Common sense tells me to List.append it, but when I try that I get:

[1;2;3;4] |> List.append [5;6];;

val it : int list = [5; 6; 1; 2; 3; 4]

Why is it prepending the values to my list instead of appending them?

Upvotes: 0

Views: 1138

Answers (4)

Vandroiy
Vandroiy

Reputation: 6223

You are absolutely right to be confused. The way this function behaves is not intuitive from its name at all. List.append actually does what (@) does:

List.append ['a'] ['b'] // ['a'; 'b']
['a'] @ ['b']           // ['a'; 'b']
(@) ['a'] ['b']         // ['a'; 'b']

If I say "append a to b", I expect the result to be ba. Take the statement "add a to the set s": it is written as Set.add a s. But List.append swaps the position of the arguments, which is especially dangerous since the arguments have the same type. Now, one could read this as "append a and b", but that's not good syntax even in spoken language.

Thus, the pipeline operator reads just as nonsensically: input |> append a is equal to append a input, which strangely translates to "append input to a" in spoken language.

If you ask me, it would have been better to pick a different name for this one.

Upvotes: 1

Gus
Gus

Reputation: 26174

It's not really prepending. You're changing the order the arguments appear by using the forward pipe operator, which in this case reverses the order but if you write the function without altering the order it makes more sense:

List.append [1;2;3;4] [5;6]   // [1;2;3;4;5;6]

Note that this is coherent with Array.append and Seq.append. It's also coherent with the string concatenation operator as function (+).

The forward operator 'moves' the last argument to the beginning of the expression, which in some cases may be desired (piping) but it may be confusing in other scenarios, take for instance the division as function (/) if you use it as part of a piping, with a forward operator:

5 |> (/) 10

It evaluates to 10 / 5 but at first sight you may get the wrong impression that it will do 5 divided by 10.

Upvotes: 16

Lee
Lee

Reputation: 144136

This is being parsed as

[1;2;3;4] |> (List.append [5;6])

and List.append [5;6] returns a function int list -> int list which appends the input to the list [5;6]. You are then applying the list [1;2;3;4] to this function.

Upvotes: 5

Daniel
Daniel

Reputation: 47904

I think this is an odd function in that the order of the args doesn't work well with pipelines. Instead the order reflects the resulting list, i.e., List.append [1;2] [3;4] yields [1;2;3;4].

Upvotes: 5

Related Questions