
Hi Sean Thanks for the comment. David Menendez pointed out on the other thread that they generalize nicely to functors: http://www.haskell.org/pipermail/haskell-cafe/2009-December/071428.html Typographically they are a pun on ML's composition operator (o), if you don't define o - (aka 'monocle' - little need as we've already got (.) ) then I'd imagine there won't be too many name clashes with people's existing code. 'Specs' was an obvious name for the family once you use them infix. Many of the combinator 'birds' that aren't already used by Haskell seem most useful for permuting other combinator birds rather than programming with - their argument orders not being ideal. The most useful ones I've found that expand to higher arities have the first argument as a 'combiner' (combining all the intermediate results), one or more 'functional' arguments (producing intermediate results from the 'data' arguments), then the 'data' arguments themselves. The liftM and liftA family are of this form, considering the functional type instances ((->) a): liftA :: (a -> ans) -> (r -> a) -> r -> ans liftA2 :: (a -> b -> ans) -> (r -> a) -> (r -> b) -> r -> ans liftA3 :: (a -> b -> c -> ans) -> (r -> a) -> (r -> b) -> (r -> c) -> r -> ans ... or the full general versions: liftA :: Applicative f => (a -> b) -> f a -> f b liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d liftA for functions is bluebird liftA2 for functions is phoenix or starling' or Big Phi ---- An arity family of Starlings can be quite nice for manipulating records. starling :: (a -> b -> c) -> (a -> b) -> a -> c star :: (a -> r -> ans) -> (r -> a) -> r -> ans star2 :: (a -> b -> r -> ans) -> (r -> a) -> (r -> b) -> r -> ans star3 :: (a -> b -> c -> r -> ans) -> (r -> a) -> (r -> b) -> (r -> c) -> r -> ans star4 :: (a -> b -> c -> d -> r -> ans) -> (r -> a) -> (r -> b) -> (r -> c) -> (r -> d) -> r -> ans star5 :: (a -> b -> c -> d -> e -> r -> ans) -> (r -> a) -> (r -> b) -> (r -> c) -> (r -> d) -> (r -> e) -> r -> ans An example - tracking the source position in a parser: data SrcPos = SrcPos { src_line :: Int, src_column :: Int, src_tab_stop :: Int } incrCol :: SrcPos -> SrcPos incrCol = star (\i s -> s { src_column=i+1 }) src_column incrTab :: SrcPos -> SrcPos incrTab = star2 (\i t s -> s { src_column=i+t }) src_column src_tab_stop incrLine :: SrcPos -> SrcPos incrLine = star (\i s -> s { src_line =i+1, src_column=1 }) src_line ---- Permuted variants of cardinal-prime can be useful for adapting a function to a slightly different type. I originally called them combfi etc. 'f' to indicate where a function was applied, and 'i' where identity was applied; but I'm no so happy with the name now: combfi :: (c -> b -> d) -> (a -> c) -> a -> b -> d combfii :: (d -> b -> c -> e) -> (a -> d) -> a -> b -> c -> e combfiii :: (e -> b -> c -> d -> f) -> (a -> e) -> a -> b -> c -> d -> f I've sometimes used them to generalize a function's interface, e.g a pretty printer: f1 :: Doc -> Doc -> Doc adapted_f1 :: Num a => a -> Doc -> Doc adapted_f1 = f1 `combfi` (int . fromIntegral) ... not particularly compelling I'll admit. Slowly I'm synthesizing sets of 'em when they seem to apply to an interesting use. Actually finding valid uses and coining good names is harder than defining them. The 'specs' were lucky in that they pretty much named themselves. Best wishes Stephen