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.
Related
How Can I instantiate the following data types to be Functor ?
data LiftItOut f a = LiftItOut (f a)
data Parappa f g a = DaWrappa (f a) (g a)
data IgnoreOne f g a b = IgnoringSomething (f a) (g b)
data Notorious g o a t = Notorious (g o) (g a) (g t)
There are not very clear for the declaration themselves, inside the parantheses in the right member, is that function application (I ve never seen that, only basic type constructors)? I am new to haskell and I am just trying to understand the basics.
Ask the compiler to show you how. Use the command line flag -ddump-deriv, enable the DeriveFunctor language extension, and put deriving Functor at the end of each type definition, and then the compiler will print Functor instances for each of them:
==================== Derived instances ====================
Derived class instances:
instance GHC.Base.Functor g =>
GHC.Base.Functor (Main.Notorious g o a) where
GHC.Base.fmap f_aK1 (Main.Notorious a1_aK2 a2_aK3 a3_aK4)
= Main.Notorious a1_aK2 a2_aK3 (GHC.Base.fmap f_aK1 a3_aK4)
(GHC.Base.<$) z_aK5 (Main.Notorious a1_aK6 a2_aK7 a3_aK8)
= Main.Notorious a1_aK6 a2_aK7 ((GHC.Base.<$) z_aK5 a3_aK8)
instance forall k (f :: k -> *) (g :: * -> *) (a :: k).
GHC.Base.Functor g =>
GHC.Base.Functor (Main.IgnoreOne f g a) where
GHC.Base.fmap f_aK9 (Main.IgnoringSomething a1_aKa a2_aKb)
= Main.IgnoringSomething a1_aKa (GHC.Base.fmap f_aK9 a2_aKb)
(GHC.Base.<$) z_aKc (Main.IgnoringSomething a1_aKd a2_aKe)
= Main.IgnoringSomething a1_aKd ((GHC.Base.<$) z_aKc a2_aKe)
instance (GHC.Base.Functor f, GHC.Base.Functor g) =>
GHC.Base.Functor (Main.Parappa f g) where
GHC.Base.fmap f_aKf (Main.DaWrappa a1_aKg a2_aKh)
= Main.DaWrappa
(GHC.Base.fmap f_aKf a1_aKg) (GHC.Base.fmap f_aKf a2_aKh)
(GHC.Base.<$) z_aKi (Main.DaWrappa a1_aKj a2_aKk)
= Main.DaWrappa
((GHC.Base.<$) z_aKi a1_aKj) ((GHC.Base.<$) z_aKi a2_aKk)
instance GHC.Base.Functor f =>
GHC.Base.Functor (Main.LiftItOut f) where
GHC.Base.fmap f_aKl (Main.LiftItOut a1_aKm)
= Main.LiftItOut (GHC.Base.fmap f_aKl a1_aKm)
(GHC.Base.<$) z_aKn (Main.LiftItOut a1_aKo)
= Main.LiftItOut ((GHC.Base.<$) z_aKn a1_aKo)
That's kind of messy-looking, but it's rather straightforward to clean up:
data LiftItOut f a = LiftItOut (f a)
instance Functor f => Functor (LiftItOut f) where
fmap f (LiftItOut a) = LiftItOut (fmap f a)
data Parappa f g a = DaWrappa (f a) (g a)
instance (Functor f, Functor g) => Functor (Parappa f g) where
fmap f (DaWrappa a1 a2) = DaWrappa (fmap f a1) (fmap f a2)
data IgnoreOne f g a b = IgnoringSomething (f a) (g b)
instance Functor g => Functor (IgnoreOne f g a) where
fmap f (IgnoringSomething a1 a2) = IgnoringSomething a1 (fmap f a2)
data Notorious g o a t = Notorious (g o) (g a) (g t)
instance Functor g => Functor (Notorious g o a) where
fmap f (Notorious a1 a2 a3) = Notorious a1 a2 (fmap f a3)
Also worth noting that your LiftItOut is isomorphic to Ap and IdentityT, and your Parappa is isomorphic to Product.
A functor f is a type constructor with an associated function fmap that from a function of type (a -> b) creates a function of type (f a) -> (f b) which applies it "on the inside": (the parentheses are redundant and are used for clarity/emphasis only)
fmap :: (Functor f) => ( a -> b)
-> (f a) -> (f b)
-- i.e. g :: a -> b -- from this
-- --------------------------
-- fmap g :: (f a) -> (f b) -- we get this
(read it "fmap of g from a to b goes from f a to f b").
Put differently, something being a "Functor" means that it can be substituted for f in
fmap id (x :: f a) = x
(fmap g . fmap h) = fmap (g . h)
so that the expressions involved make sense (i.e. are well formed, i.e. have a type), and, importantly, the above equations hold -- they are in fact the two "Functor laws".
You have
data LiftItOut h a = MkLiftItOut (h a) -- "Mk..." for "Make..."
------------- ----------- ------
new type, data type of the data constructor's
defined here constructor one argument (one field)
This means h a is a type of a thing which can serve as an argument to MkLiftItOut. For example, Maybe Int (i.e. h ~ Maybe and a ~ Int), [(Float,String)] (i.e. h ~ [] and a ~ (Float,String)), etc.
h, a are type variables -- meaning, they can be replaced by any specific type so that the whole syntactic expressions make sense.
These syntactic expressions include MkLiftItOut x which is a thing of type LiftItOut h a provided x is a thing of type h a; LiftItOut h a which is a type; h a which is a type of a thing which can appear as an argument to MkLiftItOut. Thus we can have in our programs
v1 = MkLiftItOut ([1,2,3] :: [] Int ) :: LiftItOut [] Int
v2 = MkLiftItOut ((Just "") :: Maybe String) :: LiftItOut Maybe String
v3 = MkLiftItOut (Nothing :: Maybe () ) :: LiftItOut Maybe ()
.....
etc. Then we have
ghci> :i Functor
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
..........
This means that Functor f => (f a) is a type of a thing which a variable can reference, e.g.
-- f a
v4 = Just 4 :: Maybe Int
v41 = 4 :: Int
v5 = [4.4, 5.5] :: [] Float
v51 = 4.4 :: Float
v52 = 5.5 :: Float
v6 = (1,"a") :: ((,) Int) String -- or simpler, `(Int, String)`
v61 = "a" :: String
v7 = (\x -> 7) :: ((->) Int) Int -- or simpler, `Int -> Int`
Here a is a type of a thing, f a is a type of a thing, f is a type which, when given a type of a thing, becomes a type of a thing; etc. There's no thing which can be referenced by a variable which would have the type f on its own.
All the above fs are instances of the Functor typeclass. This means that somewhere in the libraries there are definitions of
instance Functor Maybe where ....
instance Functor [] where ....
instance Functor ((,) a) where ....
instance Functor ((->) r) where ....
Notice we always have the f, and the a. f in particular can be made of more than one constituents, but a is always some one type.
Thus in this case we must have
instance Functor (LiftItOut h) where ....
(...why? do convince yourself in this; see how all the above statements apply and are correct)
Then the actual definition must be
-- fmap :: (a -> b) -> f a -> f b
-- fmap :: (a -> b) -> LiftItOut h a -> LiftItOut h b
fmap g (MkLiftItOut x ) = (MkLiftItOut y )
where
y = ....
In particular, we'll have
-- g :: a -> b -- x :: (h a) -- y :: (h b)
and we don't even know what the h is.
How can we solve this? How can we construct an h b-type of thing from an h a-type of thing when we don't even know anything about h, a, nor b?
We can't.
But what if we knew that h is also a Functor?
instance (Functor h) => Functor (LiftItOut h) where
-- fmap :: (a -> b) -> (f a) -> (f b)
-- fmap :: (a -> b) -> (LiftItOut h a) -> (LiftItOut h b)
fmap g (MkLiftItOut x ) = (MkLiftItOut y )
where
-- fmap :: (a -> b) -> (h a) -> (h b)
y = ....
Hopefully you can finish this up. And also do the other types in your question as well. If not, post a new question for the one type with which you might have any further problems.
In Learn you a Haskell, it is given that
fmap (+3) (*3)
is equivalent to
\x -> ((x*3)+3))
However, I can't understand why. Isn't it supposed to be \x -> ((x+3)*3)?
I don't know the implementation of fmap for (*3) functor, but my intuition tells me that since the functor (*3) is equivalent to \x -> x * 3, the map (+3) would be first applied and then (*3) be applied, but it is the other way around. What am I missing in here?
my intuition tells me that since the functor (*3) is equivalent to \x -> x * 3
Functions form a functor instance
instance Functor ((->) r) where ...
Those are the functions mapping from r.
Given a function g :: r -> a you can form a new function h :: r -> b with the help of f :: a -> b via h = fmap f g. It should now be clear that f :: a -> b cannot be applied first but must be applied second. That is h' = (g :: r -> a) . (f :: a -> b) does not make any sense but h = (f :: a -> b) . (g :: r -> a) does.
fmap has to obey two laws:
fmap id == id
fmap (f . g) == fmap f . fmap g
Your proposed definition, fmap' f g == g . f, satisfies the first law but violates the second law:
fmap' id f == f . id == f == id f -- OK
fmap' (f . g) h == h . (f . g)
== (h . f) . g
== (fmap' f h) . g
== fmap' g (fmap' f h)
== (fmap' g . fmap' f) h -- violation, since (.) is not commutative
The correct definition, fmap f g = f . h, satisfies both:
fmap id f == id . f == f == id f
fmap (f . g) h == (f . g) . h
== f . (g . h)
== fmap f (g . h)
== fmap f (fmap g h)
== (fmap f . fmap g) h
A "functor", in Haskell, is a higher order type, F, -- "higher order" meaning, it accepts another type variable, a (denoting any type whatever), -- such that we can have
F a fa
(a -> b) ab
-----------------
F b fmap ab fa
which is known as "flip fmap" (flip just means that the order of arguments is flipped, flip fmap fa ab == fmap ab fa). There are also some "common sense" laws it must follow.
For F ~ Maybe, say, it means
flip fmap :: Maybe a ->
(a -> b) ->
Maybe b
and for F ~ [],
flip fmap :: [] a ->
(a -> b) ->
[] b
which is more conventionally written as [a] -> (a -> b) -> [b].
In our case here, F a ~ r -> a, or more formally, F a ~ ((->) r) a, which means F ~ ((->) r),
flip fmap :: ((->) r) a ->
(a -> b) ->
((->) r) b
which is more conventionally written as (r -> a) -> (a -> b) -> (r -> b),
r -> a
a -> b
-------------
r -> b
which is the same as (r -> a) -> (a -> b) -> r -> b since with types, the arrows associate on the right, corresponding to the fact that applications associate on the left: f a b c is actually ((f a) b) c and
f a b c = d -- f a b c
f a b = \c -> d -- (f a b) c
f a = \b c -> d -- ((f a) b) c
f = \a b c -> d -- (((f) a) b) c
are all different ways to write down the same definition, and different ways to write down the same function call.
This then means we need to implement
fmap :: (a -> b) -> (r -> a) -> (r -> b)
fmap ab ra r = b
where
b =
So what could the definition be? Is it up to us to decode what goes where? Well, we must produce a b type value. The only thing we have that can do it for us, is ab :: a -> b.
Can we produce a b without it? Out of the blue? Except for erroring out, no, we can't -- we know nothing about that b type. It can be anything. So we're left with
b = ab a
a =
and now we must get an a somewhere, to use it as an argument to ab. Fortunately, ra can give it to us:
a = ra r
and r, we already got! So the types did write this implementation for us:
fmap :: (a -> b) -> (r -> a) -> (r -> b)
fmap ab ra r = b
where
b = ab a
a = ra r
or, simplifying and renaming, we get
fmap f g r = f ( g r)
= (f . g) r
by definition of the function composition, ., as
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(f . g) r = f (g r)
which is a valid syntax definition, otherwise written as
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(.) f g r = f (g r)
or
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(.) f g = \ r -> f (g r)
or
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(.) = \f g r -> f (g r)
All these are equivalent. And its type diagram
a -> b
r -> a
--------------
r -> b
As for the intuition, a functorial type value of type F A is, loosely, an F-type "something" than can somehow produce an A-type something, in some F-type sense.
The functor laws mean that F does so in some purely "structural", mechanical way, without regard to what that A value that it produces actually is. In other words, the A values do not influence how they are produced, only the F type itself determines that.
For example, Maybe Int could Maybe produce an Int. Or [Int] could produce several Ints. (*3) can also produce an Int, if we supply it with an Int argument.
What then this fmap is? What does it do? It transforms that would-be produced value. Every functor type must define its fmap, that is what makes it be a functorial type, that it defines the
instance Functor Maybe where
fmap ab (Just a) = (Just (ab a))
etc. So then, with functions r -> a, which produce that a type value promised by their type, after being applied to an argument, we transform that value by applying the transformation function to it:
fmap transf mult3 arg = tansf (mult3 arg)
which is just the definition of the functional composition itself, with arguments renamed.
So that's why, in this case,
fmap (+3) (*3) r = (+3) ((*3) r)
= (+3) (r*3)
= (r*3) + 3
we (+3) transform the value produced by (*3) in the ((->) r) sense, which is application to some user-supplied argument, r. So (*3) must be applied first, to get (it to produce) that value.
I'm learning Haskell by taking fp-course exercise. There is a question block my way. I don't know how Haskell infer lift2 (<$>) (,)'s type, and turn out Functor k => (a1 -> k a2) -> a1 -> k (a1, a2).
I have tried out lift2 (<$>)'s type, and verified by GHCI's command :t lift2 (<$>). step as follow.
I know lift2 :: Applicative k => (a -> b -> c) -> k a -> k b -> k c
I also know (<$>) :: Functor f => (m -> n) -> (f m) -> (f n)
Then by lambda calculus's Beta conversion, I can figure out lift2 (<$>)'s type is
(Applicative k, Functor f) => k (m -> n) -> k (f m) -> k (f n) by replacing a with (m -> n), b with (f m), c with (f n)
When I going to figure out lift2 (<$>) (,)'s type, It block me.
I know (,) :: a -> b -> (a,b)
And lift2 (<$>) :: (Applicative k, Functor f) => k (m -> n) -> k (f m) -> k (f n).
How does Haskell apply lift2 (<$>) to (,)?
The first variable of lift2 (<$>) is Applicative k => k (m -> n).
The to be applied value is (,) :: a -> b -> (a, b)
How the k, m, n replace by a, b?
GHCI's answer is lift2 (<$>) (,) :: Functor k => (a1 -> k a2) -> a1 -> k (a1, a2) by typing :t lift2 (<$>) (,). I cannot infer out this answer by myself.
So I have 2 questions.
1.Could someone show me the inference step by step?
2.In this case the conversion seems not be Beta conversion in lambda calculus (May be I am wrong). What the conversion is?
Type derivation is a mechanical affair.(*) The key is that the function arrow -> is actually a binary operator here, associating on the right (while the application / juxtaposition associates on the left).
Thus A -> B -> C is actually A -> (B -> C) is actually (->) A ((->) B C) is actually ((->) A) (((->) B) C). In this form it is clear that it consists of two parts so can match up with e.g. f t, noting the equivalences f ~ ((->) A) and t ~ (((->) B) C) (or in pseudocode f ~ (A ->), and also t ~ (B -> C) in normal notation).
When "applying" two type terms a structural unification is performed. The structures of two terms are matched up, their sub-parts are matched up, and the resulting equivalences are noted as "substitutions" (... ~ ...) available to be performed and ensured in further simplifications of the resulting type terms (and if some incompatibility were to be thus discovered, the type would be then rejected).
This follows a general structure / type derivation rule rooted in the logical rule of Modus Ponens:
A -> B C
--------------
B , where A ~ C
And thus,
liftA2 :: A f => ( a -> b -> c ) -> f a -> f b -> f c
(<$>) :: F h => (d -> e) -> h d -> h e
(,) :: s -> (t -> (s, t))
---------------------------------------------------------------------------------
liftA2 (<$>) (,) :: f b -> f c
---------------------------------------------------------------------------------
b ~ h d f ~ (s->)
a ~ d->e c ~ h e a ~ t->(s,t)
\_ _ _ _ _ _ _ _ _ _ _ _ _ _ a ~ d->e
----------------------------------------------------
d ~ t e ~ (s,t)
liftA2 (<$>) (,) :: f b -> f c
~ (s -> b ) -> (s -> c )
~ F h => (s -> h d) -> (s -> h e )
~ F h => (s -> h t) -> (s -> h (s,t))
(writing A for Applicative and F for Functor, as an abbreviation). The substitutions stop when there are no more type variables to substitute.
There's some freedom as to which type variables are chosen to be substituted on each step, but the resulting terms will be equivalent up to consistent renaming of the type variables, anyway. For example we could choose
~ F h => (s -> h d) -> (s -> h e )
~ F h => (s -> h d) -> (s -> h (s,t))
~ F h => (s -> h d) -> (s -> h (s,d))
The Applicative ((->) s) constraint was discovered in the process. It checks out since this instance exists for all s. We can see it by typing :i Applicative at the prompt in GHCi. Looking through the list of instances it prints, we find instance Applicative ((->) a) -- Defined in `Control.Applicative'.
If there were no such instance the type derivation would stop and report the error, it wouldn't just skip over it. But since the constraint holds, it just disappears as it does not constrain the derived type, Functor h => (s -> h t) -> (s -> h (s,t)). It's already "baked in".
The instance defines (f <*> g) x = f x $ g x but the definition itself is not needed in type derivations, only the fact that it exists. As for the liftA2, it is defined as
liftA2 h f g x = (h <$> f <*> g) x -- for any Applicative (sans the `x`)
= (h . f <*> g) x -- for functions
= (h . f) x (g x)
= f x `h` g x -- just another combinator
(yes, (<*>) = liftA2 ($) ), so
liftA2 (<$>) (,) g s = (,) s <$> g s
= do { r <- g s -- in pseudocode, with
; return (s, r) -- "Functorial" Do
}
Or in other words, liftA2 (<$>) (,) = \ g s -> (s ,) <$> g s.
With the type Functor m => (s -> m t) -> s -> m (s,t). Which is what we have derived.
(*) See also:
Haskell: how to infer the type of an expression manually
I have stumbled on this piece of code fold ((,) <$> sum <*> product) with type signature :: (Foldable t, Num a) => t a -> (a, a) and I got completely lost.
I know what it does, but I don't know how. So I tried to break it into little pieces in ghci:
λ: :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
λ: :t (,)
(,) :: a -> b -> (a, b)
λ: :t sum
sum :: (Foldable t, Num a) => t a -> a
Everything is okay, just basic stuff.
λ: :t (,) <$> sum
(,) <$> sum :: (Foldable t, Num a) => t a -> b -> (a, b)
And I am lost again...
I see that there is some magic happening that turns t a -> a into f a but how it is done is mystery to me. (sum is not even instance of Functor!)
I have always thought that f a is some kind of box f that contains a but it looks like the meaning is much deeper.
The functor f in your example is the so-called "reader functor", which is defined like this:
newtype Reader r = Reader (r -> a)
Of course, in Haskell, this is implemented natively for functions, so there is no wrapping or unwrapping at runtime.
The corresponding Functor and Applicative instances look like this:
instance Functor f where
fmap :: (a -> b) -> (r -> a)_-> (r -> b)
fmap f g = \x -> f (g x) -- or: fmap = (.)
instance Applicative f where
pure :: a -> (r -> a) -- or: a -> r -> a
pure x = \y -> x -- or: pure = const
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
frab <*> fra = \r -> frab r (fra r)
In a way, the reader functor is a "box" too, like all the other functors, having a context r which produces a type a.
So let's look at (,) <$> sum:
:t (,) :: a -> b -> (a, b)
:t fmap :: (d -> e) -> (c -> d) -> (c -> e)
:t sum :: Foldable t, Num f => t f -> f
We can now specialize the d type to a ~ f, e to b -> (a, b) and c to t f. Now we get:
:t (<$>) -- spcialized for your case
:: Foldable t, Num f => (a -> (b -> (a, b))) -> (t f -> f) -> (t f -> (b -> (a, b)))
:: Foldable t, Num f => (f -> b -> (f, b)) -> (t f -> f) -> (t f -> b -> (f, b))
Applying the functions:
:t (,) <$> sum
:: Foldable t, Num f => (t f -> b -> (f, b))
Which is exactly what ghc says.
The short answer is that f ~ (->) (t a). To see why, just rearrange the type signature for sum slightly, using -> as a prefix operator instead of an infix operator.
sum :: (Foldable t, Num a) => (->) (t a) a
~~~~~~~~~~
f
In general, (->) r is a functor for any argument type r.
instance Functor ((->) r) where
fmap = (.)
It's easy to show that (.) is the only possible implementation for fmap here by plugging ((->) r) into the type of fmap for f:
fmap :: (a -> b) -> f a -> f b
:: (a -> b) -> ((->) r) a -> ((->) r) b
:: (a -> b) -> (r -> a) -> (r -> b)
This is the type signature for composition, and composition is the unique function that has this type signature.
Since Data.Functor defines <$> as an infix version of fmap, we have
(,) <$> sum == fmap (,) sum
== (.) (,) sum
From here, it is a relatively simple, though tedious, job of confirming that the resulting type is, indeed, (Foldable t, Num a) => t a -> b -> (a, b). We have
(b' -> c') -> (a' -> b') -> (a' -> c') -- composition
b' -> c' ~ a -> b -> (a,b) -- first argument (,)
a' -> b' ~ t n -> n -- second argument sum
----------------------------------------------------------------
a' ~ t n
b' ~ a ~ n
c' ~ a -> b -> (a,b)
----------------------------------------------------------------
a' -> c' ~ t a -> b -> (a,b)
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)