elvish icon indicating copy to clipboard operation
elvish copied to clipboard

“take” should leave what is left of the input pipe behind

Open hanche opened this issue 5 years ago • 8 comments

The take command, when given only one argument (take $n), behaves like take $n (all). In other words, it consumes the entire input pipe and returns the initial $n items ( is my prompt):

⬥ put a b c | { take 1; put ----; all }
▶ a
▶ ----
⬥ 

In the above example, I think the all command should get b and c. In other words, take $n should return the $n first items, and leave the rest for later commands to consume.

If the current behaviour is desired, one can always use take $n (all) or follow take $n by nop (all).

hanche avatar Feb 23 '20 15:02 hanche

Note that the Elvish documentation says the take command was inspired by the Haskell function of the same name. That documentation is unclear on what happens if take $n is shorter than the available values but implies the remaining values are left for subsequent functions. I've never written even a trivial "hello world" program in Haskell so I don't know how itstake function behaves. Nonetheless, the proposal by @hanche seems reasonable to me since it less likely to be confusing.

krader1961 avatar Feb 24 '20 05:02 krader1961

The take function in Haskell belongs to the pure part of the language, i.e., outside of the IO monad. In that context, the notions of “consuming” values or “leaving them behind” (or not) are meaningless. In other words, the second argument is left unchanged by the function, as it has to be in a functional language.

Elvish's two argument take is exactly the same. It is functional in nature, just as Haskell's.

My proposal is about the single argument take, which is a quite different beast, as it does IO and as such has side effects. It has nothing in common with the two argument take other than the name and a small bit of semantics. Moreover, my proposal is all about the side effects.

hanche avatar Feb 24 '20 06:02 hanche

Supporting this requires take to stop working for byte input and is thus a breaking change.

Looking at the search results, most of the code should be OK. An exception is the first take here:

https://github.com/zzamboni/elvish-modules/blob/0f176b02378912f1d547f2b9249016fb27a1e4ed/git-vcsh.elv#L26

xiaq avatar May 05 '20 22:05 xiaq

If you say so – I don't see why, but assume it is because of the way structured pipes work? At least, I don't see any obvious reason why it couldn't work with byte input, in principle if not in practice.

hanche avatar May 06 '20 06:05 hanche

take does not know whether the first input will come from the value channel or the byte pipe, so it has to listen to both at the same time; this part isn't hard. But it also has to terminate as soon as one of them has a value and avoid reading the other; this part doesn't seem to be possible.

xiaq avatar May 06 '20 21:05 xiaq

Happy to be the counterexample 😉. I think that code should be pretty easy to change to use value inputs or to store the output of the command before and then run take on that. I don't even use vcsh anymore, that was one of the first modules I wrote way back then.

zzamboni avatar May 06 '20 21:05 zzamboni

This issue needs to be considered when implementing a get builtin.

krader1961 avatar Jun 27 '20 04:06 krader1961

I was just revisiting this, and noticed a broken link in the previous comment: The reference to a new get builting was surely intended to point at #1054. (Not hard to figure out how that happened.)

hanche avatar Jan 08 '23 19:01 hanche