Creating an instance without requiring a newtype dummy - haskell

Lets say I have the following:
class C a where
f :: a -> Blah
f_impl_for_d :: D a => a -> Blah
f_impl_for_d = _
newtype Alice f a = Alice (f a)
And maybe some existing instances like so:
instance C a => C [a] where ...
instance C a => C (Identity a) where ...
instance C a => C (Maybe a) where ...
What I want is an instance like this:
instance (D a, C a => C (f a)) => C (Alice f a)
As in, wherever D a is valid, and there's an instance C (f a) with the constraint C a, then I should be able to derive C (Alice f a)
For example, if I have D a, then I should have C (Alice [] a), and C (Alice Maybe a) etc.
Now I could do this:
instance D a => C a where
f = f_impl_for_d
instance C (f a) => C (Alice f a) where
f (Alice x) = f x
But that top instance is rediculously overlapping.
Any other way? The only way I've worked out is to make a newtype like so:
newtype T x = T x
instance D x => C (T x) where
f (T x) = f_impl_for_d x
instance (Functor f, C (f (T x))) => C (Alice f x) where
f (Alice x) = f (T <$> x)
But that seems somewhat convoluted. Any nicer way? I tried mucking around with quantified constraints but I didn't get far.

C a => C (f a) isn't quite what you need. You might think of it as a function C a -> C (f a) but its meaning is technically a bit more refined than that: the C a constraint can only be solved using instances; that function cannot take arbitrary arguments.
You can define a (kind of) subclass which provides such a function instead:
class (forall a. C a => C (f a)) => C1 f where
f1 :: (a -> Blah) -> (f a -> Blah)
Which then must be implemented explicitly, for example Maybe, using your current implementation of C a => C (Maybe a), and that C instance can be replaced with a default f1 f.
instance C1 Maybe where ...
instance C a => C (Maybe a) where
f = f1 f
Then you can have
instance (D a, C1 f) => C (Alice f a) where
f (Alice x) = f1 f_impl_for_d x
This is similar to the Eq1, Ord1, Show1 classes in base. The initial intent was to encode a quantified constraint (forall a. Eq a => Eq (f a)) (before they were a thing), but technically these classes are slightly more expressive than that because the constraint Eq a (which identifies a globally unique value) is replaced with a type (which may have many values).

Related

Is there a name for this subset of bifunctors?

Bifunctors have a map function with this signature:
bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
You could also have a map like this:
othermap :: ((a, c) -> (b, d)) -> p a c -> p b d
Types with this function are a strict subset of bifunctors (you can always define bimap using othermap but not vice versa). Is there a name for the second signature?
Follow-up: what about this intermediate function?
halfothermap :: ((a, c) -> b) -> (c -> d) -> p a c -> p b d
A type which is a Bifunctor need not have the same number of a values as b values. Consider, for example,
data TwoLists a b = TwoLists [a] [b]
It is easy to implement bimap, but othermap is a real problem, especially if one of the lists is empty.
othermap f (TwoLists [] (b:bs)) = TwoLists [] _
What can you do here? You need to call f to convert all the bs to a list of type [d], but you can only call that function if you have an a in hand.
Perhaps even worse is a type which doesn't really ever have b values at all:
data TaggedFunction k a b = TaggedFunction a (k -> b)
instance Bifunctor (TaggedFunction k) where
bimap f g (TaggedFunction a b) = TaggedFunction (f a) (g . b)
How can you implement othermap for this type? You could update the function, because you have an a in hand and will have a b by the time you need a d. But there's no way for you to replace the a with a c, because you can't get hold of a b to call othermap's function with.
So you can't put this function in Bifunctor. Perhaps you're asking, why not put this in a new class? I think leftroundabout is right that the class is too constraining to be useful. othermap can be defined only when you have the same number of as and bs in your structure, i.e. when your structure is some functor f wrapped around a tuple of type (a, b). For example, instead of TwoLists we could have defined
newtype PairList a b = PairList [(a, b)]
and that can have an othermap definition. But it would just be
othermap f (PairList vs) = PairList (fmap f vs)
Likewise instead of TaggedFunction we could have defined
newtype MultiFunction k a b = MultiFunction (k -> (a, b))
but the othermap definition is again just a wrapped call to fmap:
othermap f (MultiFunction g) = MultiFunction (fmap f g)
So perhaps the best way to imagine defining this abstraction would be as, not a typeclass function, but an ordinary function that operates over a type that captures this composition:
newtype TupleFunctor f a b = TupleFunctor (f (a, b))
othermap :: Functor f => ((a, b) -> (c, d))
-> TupleFunctor f a b -> TupleFunctor f c d
othermap f (TupleFunctor x) = TupleFunctor (fmap f x)
(Expanding on a comment by #glennsl...)
The type p a c "contains" both a and c.
But a function of type (a, c) -> (b, d) requires values of type a and c to be called, and a value of type p a c doesn't necessarily have both.
othermap #Either :: ((a, c) -> (b, d)) -> Either a c -> Either b d
othermap f (Left x) = ?
othermap f (Right y) = ?
There's no way for othermap to produce values of type b or d, because it can't call f in either case.
The type of the first argument implies a bifunctor that is isomorphic to (,), which is not true of all possible bifuntors. othermap is, in fact, strictly more specific than bimap. (There seems to be a contravariant relationship here that I won't try to make precise.)

Haskel - instance of data with two arguements

How to declare Functor instance of this data type:
data Productish a b = Productish a b
I've tried this:
instance (Functor a, Functor b) => Productish a b where
fmap f (Productish a b) = Productish (f a) (f b)
but compiler had showed error:
error: ‘fmap’ is not a (visible) method of class ‘Productish’
Firstly, your syntax is wrong. To define a Functor instance on Productish, you will need to do instance Functor (Productish a b) where ….
But there is also a more serious problem: The Functor typeclass can only be used to define a functor on one variable. So in order to define a Functor instance, you need to partially apply your data type. For instance, here’s the Maybe instance:
data Maybe a = Just a | Nothing
instance Functor Maybe where -- note that this isn’t ‘instance Functor (Maybe a)’!
fmap f (Just a) = Just (f a)
fmap f Nothing = Nothing
Similarly, to define a Functor instance for your Productish, you need to do:
instance Functor (Productish a) where
fmap f (Productish a b) = Productish a (f b)
(Note that you don’t need a Functor constraint on a, since you don’t need to map over a.)
So with Functor alone, you can only map over the second argument.
Luckily, there is also a typeclass which lets you map over both arguments. It’s called Bifunctor, and lives in the Data.Bifunctor module:
class Bifunctor p where
bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
first :: (a -> b) -> p a c -> p b c
second :: (b -> c) -> p a b -> p a c
So to make a Bifunctor instance for your Productish type, use:
instance Bifunctor Productish where
bimap f g (Productish a b) = Productish (f a) (g b)
first f p = bimap f id p
second g p = bimap id g p

In Data.Data, why does gmapM take a Monad rather than an applicative?

gmapM seems like the obvious candidate for writing a generic traversal based on Data.Data, for instance, if one wants to implement MonoTraversable. The only hiccup is that it takes a Monad rather than an Applicative. Why is that? Also, is there a similar function to fmapM with weaker assumptions?
It looks like a historical detail from before implementing the Monad-Applicative proposal.
I can define both the gmapM default and the instance for lists in terms of Applicative.
gmapM :: forall m a. (Data a, Applicative m) => (forall d. Data d => d -> m d) -> a -> m a
gmapM f = gfoldl k pure
where
k :: Data d => m (d -> b) -> d -> m b
k c x = c <*> f x
-- instance Data a => Data [a] where ...
gmapMlist :: forall m a. (Data a, Applicative m) => (forall d. Data d => d -> m d) -> [a] -> m [a]
gmapMlist _ [] = pure []
gmapMlist f (x:xs) = (:) <$> f x <*> f xs

What's distributing a functor over a tuple called?

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 ->).
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.

How to construct an Applicative instance with constraints (similarly to constructing Monad instances using ContT)

This question deals with constructing a proper Monad instance from something that is a monad, but only under certain constraints - for example Set. The trick is to wrap it into ContT, which defers the constraints to wrapping/unwrapping its values.
Now I'd like to do the same with Applicatives. In particular, I have an Applicative instance whose pure has a type-class constraint. Is there a similar trick how to construct a valid Applicative instance?
(Is there "the mother of all applicative functors" just as there is for monads?)
What may be the most consistent way available is starting from Category, where it's quite natural to have a restriction to objects: Object!
class Category k where
type Object k :: * -> Constraint
id :: Object k a => k a a
(.) :: (Object k a, Object k b, Object k c)
=> k b c -> k a b -> k a c
Then we define functors similar to how Edward does it
class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where
fmap :: (Object r a, Object t (f a), Object r b, Object t (f b))
=> r a b -> t (f a) (f b)
All of this works nicely and is implemented in the constrained-categories library, which – shame on me! – still isn't on Hackage.
Applicative is unfortunately a bit less straightforward to do. Mathematically, these are monoidal functors, so we first need monoidal categories. categories has that class, but it doesn't work with the constraint-based version because our objects are always anything of kind * with a constraint. So what I did is make up a Curry class, which kind of approximates this.
Then, we can do Monoidal functors:
class (Functor f r t, Curry r, Curry t) => Monoidal f r t where
pure :: (Object r a, Object t (f a)) => a `t` f a
fzipWith :: (PairObject r a b, Object r c, PairObject t (f a) (f b), Object t (f c))
=> r (a, b) c -> t (f a, f b) (f c)
This is actually equivalent to Applicative when we have proper closed cartesian categories. In the constrained-categories version, the signatures unfortunately look very horrible:
(<*>) :: ( Applicative f r t
, MorphObject r a b, Object r (r a b)
, MorphObject t (f a) (f b), Object t (t (f a) (f b)), Object t (f (r a b))
, PairObject r (r a b) a, PairObject t (f (r a b)) (f a)
, Object r a, Object r b, Object t (f a), Object t (f b))
=> f (r a b) `t` t (f a) (f b)
Still, it actually works – for the unconstrained case, duh! I haven't yet found a convenient way to use it with nontrivial constraints.
But again, Applicative is equivalent to Monoidal, and that can be used as demonstrated in the Set example.
I'm not sure the notion of "restricted applicative" is unique, as different presentations are not isomorphic. That said here is one and something at least somewhat along the lines of Codensity. The idea is to have a "free functor" together with a unit
{-# LANGUAGE TypeFamilies, ConstraintKinds, ExistentialQuantification #-}
import GHC.Prim (Constraint)
import Control.Applicative
class RFunctor f where
type C f :: * -> Constraint
rfmap :: C f b => (a -> b) -> f a -> f b
class RFunctor f => RApplicative f where
rpure :: C f a => a -> f a
rzip :: f a -> f b -> f (a,b)
data UAp f a
= Pure a
| forall b. Embed (f b) (b -> a)
toUAp :: C f a => f a -> UAp f a
toUAp x = Embed x id
fromUAp :: (RApplicative f, C f a) => UAp f a -> f a
fromUAp (Pure x) = rpure x
fromUAp (Embed x f) = rfmap f x
zipUAp :: RApplicative f => UAp f a -> UAp f b -> UAp f (a,b)
zipUAp (Pure a) (Pure b) = Pure (a,b)
zipUAp (Pure a) (Embed b f) = Embed b (\x -> (a,f x))
zipUAp (Embed a f) (Pure b) = Embed a (\x -> (f x,b))
zipUAp (Embed a f) (Embed b g) = Embed (rzip a b) (\(x,y) -> (f x,g y))
instance Functor (UAp f) where
fmap f (Pure a) = Pure (f a)
fmap f (Embed a g) = Embed a (f . g)
instance RApplicative f => Applicative (UAp f) where
pure = Pure
af <*> ax = fmap (\(f,x) -> f x) $ zipUAp af ax
EDIT: Fixed some bugs. That is what happens when you don't compile before posting.
Because every Monad is a Functor, you can use the same ContT trick.
pure becomes return
fmap f x becomes x >>= (return . f)

Resources