I just defined maybe the gnarliest regex of my life to look for anything resemblilng f (f a -> f b) -> f a -> f b in the source code, and no dice:
-- Haskell:
word = "[0-9a-zA-Z_]\\+ *"
lp = "( *"
rp = ") *"
arrow = "\\-> *"
w2 = word ++ word
f2 = word ++ word ++ arrow ++ word ++ word -- func from 2 words to 2 words
re = word ++ lp ++ f2 ++ rp
++ arrow ++ w2
++ arrow ++ w2
-- Emacs: In `re`, replace each \\ with \, because I apparanetly still don't understand strings in Haskell well enough.
-- Shell:
grep -i "[0-9a-zA-Z_]\+ *( *[0-9a-zA-Z_]\+ *[0-9a-zA-Z_]\+ *\-> *[0-9a-zA-Z_]\+ *[0-9a-zA-Z_]\+ *) *\-> *[0-9a-zA-Z_]\+ *[0-9a-zA-Z_]\+ *\-> *[0-9a-zA-Z_]\+ *[0-9a-zA-Z_]\+ *" -r . --color
There's actually one match, in "tidal-parse/src/Sound/Tidal/Parse.hs", but that's not relevant.
The type alone does not tell me what you expect the function to do. What laws do you expect to hold? Would this work for other Applicatives? I guess you need Monad as well?
I built this, which has the type you want:
\ g x -> join (fmap (\h -> h . pure ) g <*> x )
:: (Monad m, Applicative f) => m (f a1 -> m a2) -> m a1 -> m a2
if m = f = Pattern, then for join, there are three choices (inner, outer, squeeze), and for <*> there are as well (structure from left, right, both)
I agree that it's not clearly a great candidate for a typeclass. I don't know what rules it should satisfy for other types.
For the Pattern type, the law it should satisfy is, I believe, this:
If
f :: Pattern ( Pattern a -> Pattern b )
a :: Pattern a
b :: Pattern b
s :: State
and query f s yields a single event e covering the entire timespan of s with the payload g :: a -> b, then query (f <**> a) s should be equal to query (g a) s.
don't think there's a short mininotation for a pattern of functions, though
I thought about that and it seems hard. But it's easy to make a pattern of words (or numbers) and then use a lookup function to replace the words (or numbers) with functions. The awkward part is that since some functions take arguments, you'll need to apply the arguments in the lookup table rather than in the pattern -- but it's nice and simple:
funcPat :: forall a b label. Show label
=> [(label, Pattern a -> Pattern b)]
-> Pattern String
-> Pattern (Pattern a -> Pattern b)
funcPat funcs labelPat = let
m :: Map String (Pattern a -> Pattern b)
m = M.fromList $ map (_1 %~ show) funcs
in filterJust $ fmap (flip M.lookup m) labelPat
(That function could be more general, too -- the Pattern a -> Pattern b could be swapped out for a type variable.)