Is there a name for this family of operations?
Functor f => f (a, b) -> (f a, f b)
Functor f => f (a, b, c) -> (f a, f b, f c)
...
Functor f => f (a, b, ..., z) -> (f a, f b, ..., f z)
They're easy to implement, just trying to figure out what to call it.
\fab -> (fst <$> fab, snd <$> fab)
For me, it came up in the context of f ~ (x ->)
.
Tuple as a functor Doing this for a pair, which in C# has the type Tuple<T, U> , this means that tuples are functors if we keep T fixed and enable translation of the second element from U1 to U2 . You simply return a new tuple by carrying source.
Functor in Haskell is a typeclass that provides two methods – fmap and (<$) – for structure-preserving transformations. To implement a Functor instance for a data type, you need to provide a type-specific implementation of fmap – the function we already covered.
In Haskell, an applicative is a parametrized type that we think of as being a container for data of that type plus two methods pure and <*> . Consider a parametrized type f a . The pure method for an applicative of type f has type. pure :: a -> f a. and can be thought of as bringing values into the applicative.
String is not a functor, because it has the wrong kind. String :: Type , but a functor has to have kind Type -> Type . Before we talk about Tree , let's establish a few facts. Sum types are functors, if the components are functors.
In your specific context f ~ (x ->)
, I think they can be called "power laws".
Indeed, in theory, it is common to write A -> B
as the power B^A
. The pair type (A,B)
is also commonly written as a product (A*B)
.
Your first law is then written as
(A*B)^C = A^C * B^C
and is a classic type isomorphism. This can be easily generalized to tuples in the obvious way.
In the general case, where f
is an arbitrary functor, I can't think of nothing else than "distribution", right now.
There is Data.Distributive
which is the dual of Data.Traversable
. It provides the distribute
function which can be specialized e.g. as f (Stream a) -> Stream (f a)
or distribute :: f (Vec n a) -> Vec n (f a)
. The latter example is a homogeneous variant of your family of functions.
But we can generalize Data.Distributive
a bit just like lenses generalize functors. Enter Colens
:
type Colens s t a b = forall f. Functor f => (f a -> b) -> f s -> t
Here is the mirror of Control.Lens.Each
:
class Coeach s t a b | s -> a, t -> b, s b -> t, t a -> s where
coeach :: Colens s t a b
instance (a~a', b~b') => Coeach (a,a') (b,b') a b where
coeach f p = (f $ fst <$> p, f $ snd <$> p)
instance (a~a2, a~a3, b~b2, b~b3) => Coeach (a,a2,a3) (b,b2,b3) a b where
coeach f p = ...
...
And just like with each
we can iterate over tuples
each_id1 :: Applicative f => (f a, f a) -> f (a, a)
each_id1 = each id
each_id2 :: Applicative f => (f a, f a, f a) -> f (a, a, a)
each_id2 = each id
with coeach
we can coiterate over tuples:
coeach_id1 :: Functor f => f (a, a) -> (f a, f a)
coeach_id1 = coeach id
coeach_id2 :: Functor f => f (a, a, a) -> (f a, f a, f a)
coeach_id2 = coeach id
This is still homogeneous, though. I don't know lens
much, so can't say whether there is a heterogeneous each
and the corresponding coeach
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With