What are all_groups
, current_group
, size
?
These are the three pieces of state required to produce the groupings by visiting each item in the input sequence. These individual states are combined in a 3-tuple to form a single state for the fold. Ultimately we'll only care about all_groups
, and the other two are just intermediate state necessary to construct that.
all_groups
: This is a list value that accretes completed groupings. Whenever we've seen enough new elements to satisfy the group size, we make a new group and add it to this list.
current_group
: This is also a list value, but more of a temporary buffer to build up a grouping until it reaches size
. When it's big enough, it gets added to all_groups
and is reset to a new group/list with the current item [x]
.
size
this is just a counter to track how many items are in current_group
.
What does this do?
if size = 3
simply decides whether we want to keep accumulating elements or if we've got enough for a grouping.
then ( (List.rev current_group) :: all_groups, [x], 1 )
is building/returning the new accumulator value, which is a 3-tuple of all_groups
, current_group
, and size
. The List.rev
call is necessary because of the way the list is being grown, in the else branch; it's fastest to add items to the front of a list, but this is the reverse of the input sequence thus we reverse them. x
is the current item, which will be the first item in the new, growing group. 1
is of course the size of that new group.
else ( all_groups, x::current_group, size+1)
is popping the current item x
onto the front of the current_group
list and incrementing the size
counter.
Below that section is the logic that takes care of any straggler items that don't fit neatly into groupings of three.