How to replace deprecated operator <~>

Hi all! I'm looking into some old code and can not figure out how to replace a very handy operator, which saved a lot of typing:

<~> -- Pattern replacement: takes the elements of the second pattern and makes a new pattern using the structure of the first

For example:

d1 $ n ("x*8" <~> "a6*45 e6*8 f6*45 g6*4") # s "arpy"

would sound as:

 d1 $ cat [
  n "a6*8",
  n "a6*8",
  n "a6*8",
  n "a6*8",
  n "a6*8",
  n "e6*8",
  n "f6*8",
  n "f6*8",
  n "f6*8",
  n "f6*8",
  n "f6*8",
  n "g6*8"
] # s "arpy"

I'd say some use of the struct function could do the trick, but from your example I'm failing to infer how <~> worked precisely. Does a6*45 give rise to 5 copies of a6*8 because the euclidean division of 45 by 8 yields 5? If so, how comes g6*8 is present at all?
Could you direct us to where you found this place of documentation?

I'm guessing a6*45 is a typo? maybe it should be a6*5
By the way, +1 for this, this function is very useful

The "preplace" family of functions has always been a little weird since internally they force Patterns to act as lists and then turn things back into a Pattern, and sometimes this has strange or unpredictable results.

But I think I got something working. Had to change some details slightly because of "Overlapping Instance" problems so there might be some issues. I'll test it out a bit and submit a PR if it seems to work but for now you can copy/paste this to get the <~> operator working again:

import Data.List (sortBy)

prrw :: (a -> b -> c) -> Int -> (Time, Time) -> Pattern a -> Pattern b -> Pattern c
prrw f rot (blen, vlen) beatPattern valuePattern =
    ecompare ev1 ev2 = compare (start $ part ev1) (start $ part ev2)
    beats = sortBy ecompare $ queryArc beatPattern (Arc 0 blen)
    values = fmap value . sortBy ecompare $ queryArc valuePattern (Arc 0 vlen)
    cycles = blen * (fromIntegral $ lcm (length beats) (length values) `div` (length beats))
    _slow cycles $ stack $ zipWith
      (\ev v -> ((start $ part ev) `rotR`) $ _fastGap (1 / ((stop $ part ev) - (start $ part ev))) $ pure (f (value ev) v))
      (sortBy ecompare $ queryArc (_fast cycles $ beatPattern) (Arc 0 blen))
      (drop (rot `mod` length values) $ cycle values)

prr :: Int -> (Time, Time) -> Pattern String -> Pattern a -> Pattern a
prr = prrw (flip const)

preplace = prr 0

(<~>) = preplace (1,1)

This is amazing! I'm super hyped for this.
I'm still getting Overlapping Instances here, though. Is there a ghc flag we need to enable or something?

I don't think so, can you post a full example of what gave the error?

In the long run, and for consistency, it may be better to switch the preplace-style functions so that they use Pattern Bool so you'd use "t*8" <~> "a6*45 e6*8" instead of putting "x" characters in there.

1 Like

Nevermind, I just forgot to parse the type signatures, and they turn out to be important, now it's working! :slight_smile:
Incredible job with this function, and +1 for the bool mask, it makes a lot of sense

This is magic for muggles! Thank you.