I think it simply comes from how it's implemented:
ply :: Pattern Int -> Pattern a -> Pattern a
ply = tParam _ply
_ply :: Int -> Pattern a -> Pattern a
_ply n p = arpeggiate $ stack (replicate n p)
Basically, the arpeggiate is here to have the elements in stack spread out instead of played all at once, which has the side effect of also spreading the elements of the chord, since a chord really only is a list of notes played at the same time.
I'm unsure how one would go about doing what you were going for to begin with. It would involve distinguishing the multiple notes arising from the chords from the ones arising from the replicate, which I don't see an obvious way of doing.
Thanks for your kind words! I knew that I had seen this kind of code before
The second lines are not obtainable by a command that I know of. You can either navigate to https://github.com/tidalcycles/Tidal/ and type the name of the function in the search bar and then do your best to locate the place in the source code where it's defined, or you can use Hoogle to find your function (make sure to pick the one that is actually part of Tidal, sometimes there are homonyms), and then get to the source code like this. Both solutions are mostly equivalent, it's a matter of taste which one you prefer.
Wow Alex! I didn't even think it was a bug. I usually suspect my lack of understanding in such cases. Thanks for digging into it. I am continually amazed at the responsiveness, patience, and helpfulness of everyone in the tidalcycles community.
No problem! I'm so happy with this solution and it's giving me new ideas for how to deal with syncopation etc.
squeezeJoin $ (_fast n . pure) <$> pat can be translated to english quite neatly:
For every value in a pattern (<$>), turn that value into its own pattern, triggering once per cycle (pure) and repeat it the given number of times (_fast n). Then you have close to what you want, but it's a pattern of patterns of values, and not a pattern of values. So you want to take one cycle from each pattern inside the pattern, and squeeze that into the timespan that the original value had (squeezeJoin). A lot nicer than expressing it in terms of duplicating events, manipulating time arcs etc..