byorgey / species

Other
17 stars 1 forks source link

How do I project the Hadamard product or :*: of two species to a component of it? #5

Open inthar-raven opened 7 months ago

inthar-raven commented 7 months ago

I might have missed this part of the documentation, but I can't seem to find a way to destructure elements of my custom species which is a Hadamard product:

-- Species of musical scales with abstract steps (necklaces) with exactly `r` distinguished letters.
-- The species is the Hadamard product of the species of cycles and the species of ballots with exactly `r` nonempty parts.
-- The printed output has the form `(<scale steps in cyclic order>,[{steps of size x_1},{steps of size x_2},...,{steps of size x_r}])`.
necklaceOfExactArity :: Integer -> SpeciesAST
necklaceOfExactArity r = Math.Combinatorics.Species.cycle >< ((linOrd `ofSizeExactly` r) `o` (nonEmpty sets) )

where the shape of species necklaceOfExactArity r is of type

type Scale = (Structures.:*:) Structures.Cycle ((Structures.:.:) [] Set)

I can get a list of shapes using [0..n-1] as labels with no issue, and each shape should morally be represented as a pair (cycle, list of lists of labels), but I don't know how to access an element of this pair. Is there a reason why Math.Combinatorics.Species.Structures doesn't export the pFst and pSnd projection functions which should do just that?

inthar-raven commented 7 months ago

Adding this to my module fixed it:

import Math.Combinatorics.Species.Structures ((:*:))
-- Utility functions for projecting Hadamard products of species.
pFst :: ((:*:) f g) a -> f a
pFst ((:*:) x y) = x

pSnd :: ((:*:) f g) a -> g a
pSnd ((:*:) x y) = y

pSwap :: ((:*:) f g) a -> ((:*:) g f) a
pSwap ((:*:) x y) = (:*:) y x

It would still be nice if the package exported these functions, though.

byorgey commented 7 months ago

Thanks for the report! You're right that there's no reason we can't export pFst and pSnd, that was probably just an oversight. (Though really, perhaps we ought to now just re-export Data.Functor.Product.) But to answer your original question, the way to destructure elements built with :*: is by pattern matching. In my experience, any time I find myself using functions like fst and snd, there is usually a cleaner way to write the code by directly pattern-matching on the pair.