Tidal has four functions of type Pattern (Pattern a) -> Pattern a
. (squeeze|inner|outerJoin|unwrap).
Each such join
can be used to define bind
, in a Monad
instance, and this gets used when we write do
notation.
I find squeezeJoin
most useful for defining global structure, and I'd like to write
d1 $ do
b <- segment 2 $ irand 7
stack
[ s "supersaw" + nsm (b - "[14 [~ 10]]")
, do
e <- segment 2 $ irand 3
d <- segment 1 $ irand 2
s "superpwm"
+ nsm (b + (d + 1) * run (2^e) )
]
but this does not work as expected since instance Monad Pattern
uses unwrap
.
Full code, for comparison: https://git.imn.htwk-leipzig.de/waldmann/computer-mu/-/tree/master/tidal/code/bind (beware, the snippet sounds terrible, but it shows the idea)
I am not really suggesting to make that change now - I think what I am asking is: what was the reason to define bind
via unwrap
?
Oh, and I should also be asking - do any of these four obey Monad laws (modulo some observational equivance)?
[EDIT] well one reason certainly is that bind-via-unwrap fits with <*>
let m1 = fastcat [ pure succ, pure pred ]
m2 = fastcat @Integer [2, 4, 8]
m1 <*> m2
==> (0>⅓)|3 (⅓>½)|5 (½>⅔)|3 (⅔>1)|7
m1 >>= (\x1 -> m2 >>= (\x2 -> return (x1 x2)))
==> same as above,
as it shold be, https://hackage.haskell.org/package/base-4.21.0.0/docs/Control-Applicative.html#t:Applicative, "if f is also a Monad",
while this gives something different
let bind p f = squeezeJoin (fmap f p)
m1 `bind` (\x1 -> m2 `bind` (\x2 -> return (x1 x2)))
==> (0>⅙)|3 (⅙>⅓)|5 (⅓>½)|9 (½>⅔)|1 (⅔>⅚)|3 (⅚>1)|7
Still I wonder - what are known use cases of do
notation for patterns?