Right now we have List.drop to drop the first n elements from a list. What do folks think about adding in a function that drops the last n elements from a list? I found myself wanting it a few days ago.
I’m not sure what a good name for it would be. I think dropFirst and dropLast would make sense but those are already taken.
Perhaps dropStart and dropEnd?
I like it.
Double check if we have mirrored apis around first and last
I feel like we do with take or split or something, but I don't think the naming is consistent
There may be a couple of naming/consistency changes that are wanted here
Oh, just realized that you mentioned the other names.
I think we should brainstorm names in general cause this could be a repeated API keep or take as well.
I also, would personally prefer if dropFirst did what you would expect from dropFirstN.
Could also maybe try dropUpTo?
What’s the policy for renaming functions? Is there a deprecation process or just go for it?
Could also maybe try dropUpTo?
It’s not clear to me what dropUpTo is supposed to do when I hear that name
just go for it :+1:
Random thought:
list |> drop (First 5)
list |> drop (Last 5)
list |> drop (Between 2 7)
list |> drop (Where \x -> x > 0)
Oh wow, that’s a cool idea!
It is very pleasing to unify all those functions. That said, the downsides that occur to me are that then you need to use more parens, you can’t use the trailing lambda syntax as nicely, and the type signature gets more complicated
What do others think?
Slight extension of that: that thing in parens (call it a predicate) could be used in other functions, e.g. list |> take (Last 5) (just returns the last five elements of the list), and list |> split (Where \x -> x > 0) returns a pair of lists, one where the first list is all the elements that matched the predicate, and the second list is all the elements that didn't. You could even pass that around as a first-class value. Haven't really thought thru the implications/uses for that yet... :thinking:
I think dropIf is nice because it matches up with keepIf and countIf. Otherwise though something like drop : List a, [First Nat, Last Nat, At Nat, Between Nat Nat] -> List a is nice.
Between is maybe a bit awkward because usually when a function takes a range we specify if the start/end is inclusive/exclusive, like List.range list { start: After 2, end: Before 5 }. It could be list |> drop (Within { start: After 2, end: Before 5 }), but that's a bit ornate.
I think it would be best to either use an approach like this for many applicable functions throughout the builtins or not much at all. But that would be a big change
Joshua Warner said:
Random thought:
list |> drop (First 5)
list |> drop (Last 5)
list |> drop (Between 2 7)
list |> drop (Where \x -> x > 0)
I do wonder if adding the extra function argument incurs some runtime cost, or if the extra argument gets optimized out?
For always the same tag, should just optimize away
Though if optimization fails, will be an extra branch
I would generally expect it to inline and optimize away, but confidence in that is hard to say for sure.
Personally, I think we should keep it split. I think that Where is better without the parens as dropif. I also think that between is too complex and we shouldn't support it. Look at list.range above for complexities.
I would push for just first and last just taking N as an arg. Then is it one simple API with a minor cost of verbosity when dropping exactly one element
I would push for just first and last just taking N as an arg. Then is it one simple API with a minor cost of verbosity when dropping exactly one element
I agree :check:
Quick q - how are we meant to implement functions like keepIf and dropIf for cases where the condition should depend on the index? It's super common to want to transform the elements of a list based on their indices.
Some sort of mapWithIndex followed by a keep. Or some sort of direct walk with extra state
Yeah it's worth knowing that walk is the most general of the iteration functions. You can build any of the others from it. And in fact, a lot of them are implemented that way.
I figured that out, but how many bugs have been caused by needing to do your own index maths? It's such an important case that it might be worth giving a little help
I think we have walk with index as well
Oh good. Then all that's left is how to make keepIf and dropifwork nicely with indices. Maybe just play with its type so it can take either a function that accepts the list type alone, or the list type and a nat, with the innards branching on the choice?
If you are using indices, do you need it as part of keepIf? I would expect you would first extra a sublist or similar. When would both be needed but sublist not work?
Last updated: Jun 16 2026 at 16:19 UTC