Does such a thing exist in Haskell's Prelude?
wfmap :: Functor f
=> a
-> (a -> b)
-> (b -> a)
-> (b -> f b)
-> f a
wfmap x u w g = fmap (w) (g (u x))
In a project I'm working on, I often found myself 'converting' a type to another, process it and 'converting' it back.
Reordering the arguments, as leftaroundabout suggests, allows for a tidier definition:
wfmap :: Functor f => (a -> b) -> (b -> a) -> (b -> f b) -> a -> f a
wfmap u w g = fmap w . g . u
As for library support, lens provides nifty support for isomorphisms. A bit more broadly, as Gurkenglas notes...
Functor f => (b -> f b) -> a -> f a is also called Lens' a b and is the centerpiece of the lens library.
Without diving into the details of how and why that works, one consequence is that your function might be defined as:
wfmap :: Functor f => (a -> b) -> (b -> a) -> (b -> f b) -> a -> f a
wfmap u w g = (iso u w) g
Or even:
wfmap :: Functor f => (a -> b) -> (b -> a) -> (b -> f b) -> a -> f a
wfmap = iso
wfmap is just (a specialised version of) iso, which gives out a function which can be used to convert an b -> f b function on the isomorphism "destination" to an a -> f a one on the isomorphism "source".
It is also worth mentioning mapping, which can be used for the somewhat different purpose of applying fmap on the other side of an isomorphism:
GHCi> :t \u w g -> over (mapping (iso u w)) (fmap g)
\u w g -> over (mapping (iso u w)) (fmap g)
:: Functor f => (s -> a) -> (b -> t) -> (a -> b) -> f s -> f t
GHCi> :t \u w g -> under (mapping (iso u w)) (fmap g)
\u w g -> under (mapping (iso u w)) (fmap g)
:: Functor f => (s -> a) -> (b -> a1) -> (a1 -> s) -> f b -> f a
Finally, note that iso u w can be replaced by any Iso you might find in the libraries or have predefined elsewhere.
Related
Chapter 16 of "Haskell Programming from First Principles" on page 995 has an exercise to manually work out how (fmap . fmap) typechecks. It suggests substituting the type of each fmap for the function types in the type of the composition operator:
T1 (.) :: (b -> c) -> (a -> b) -> a -> c
T2 fmap :: Functor f => (m -> n) -> f m -> f n
T3 fmap :: Functor g => (x -> y) -> g x -> g y
By (attempting to) substitute T2 and T3 into T1, I arrived at the following:
T4: ((m -> n) -> f m -> f n) -> ((x -> y) -> g x -> g y) -> a -> c
Further, it suggests checking the type of (fmap . fmap) to see what the end type should look like.
T5: (fmap . fmap) :: (Functor f1, Functor f2) => (a -> b) -> f1 (f2 a) -> f1 (f2 b)
I'm having trouble understanding what I should be doing here. Could any knowledgeable haskellers help get me started, or maybe provide examples of similar exercises that show how to work out types by hand?
We proceed step by careful step:
--- fmap . fmap = (.) fmap fmap
--- Functor f, g, ... => .....
(.) :: ( b -> c ) -> (a -> b ) -> a -> c
fmap :: (d -> e) -> f d -> f e
-------- ----------
(.) fmap :: (a ->d->e) -> a -> f d -> f e
---- ----------
-- then,
(.) fmap :: ( a -> d -> e ) -> a -> f d -> f e
fmap :: (b -> c) -> g b -> g c
-------- --- ---
(.) fmap fmap :: (b->c) -> f (g b) -> f (g c)
------ ----- -----
It is important to consistently rename all the type variables on each separate use of a type, to avoid conflation.
We use the fact that the arrows associate on the right,
A -> B -> C ~ A -> (B -> C)
and the type inference rule is
f :: A -> B
x :: C
--------------
f x :: B , A ~ C
(f :: A -> B) (x :: C) :: B under the equivalence / unification of types A ~ C and all that it entails.
I have a lens(')
myLens' :: (Functor f) => (a -> f a) -> (s -> f s)
And I need a function
lensWithoutFunctor' :: ((a -> b) -> (f a -> f b)) -> (a -> f a) -> (s -> f s)
(The particular type I'm interested in is
type PopType x a = x -> Maybe (a, x)
which could be made into a Functor if I wanted)
Is there a better way to do this other than create a Functor-implementing newtype and then doing something involving "ala"?
Some playing around with functors and monads in ghci led me to a value whose type and behaviour I would like to understand better.
The type of \x -> join . x is (Monad m) => (a -> m (m b)) -> (a -> m b) and the type of \y -> y . (flip fmap) is (Functor f) => ((a -> b) -> f b) -> (f a -> c).
Version 8.2.2 of ghci permits the definition h = join . (flip fmap).
Why does h have type ((A -> B) -> A) -> (A -> B) -> B?
In particular, why do the functor and monad constraints disappear? Is this really the correct and expected behaviour? As a follow up, I would also like to ask:
Why does evaluating h (\f -> f u) (\x -> x + v) for integers u and v give u + 2v in every case?
In short: due to type deduction, Haskell knows that m and f are in fact a partially instantiated arrow.
Deriving the type
Well let us do the math. The function join . (flip fmap) is basically your given lambda expression \x -> join . x with as argument (flip fmap), so:
h = (\x -> join . x) (flip fmap)
Now the lambda expression has type:
(\x -> join . x) :: Monad m => (a -> m (m b)) -> (a -> m b)
Now the argument flip fmap has type:
flip fmap :: Functor f => f c -> ((c -> d) -> f d)
(we here use c and d instead of a and b to avoid confusion between two possibly different types).
So that means that the type of flip fmap is the same as the type of the argument of the lambda expression, hence we know that:
Monad m => a -> m (m b)
~ Functor f => f c -> ((c -> d) -> f d)
---------------------------------------
a ~ f c, m (m b) ~ ((c -> d) -> f d)
So we now know that a has the same type as f c (this is the meaning of the tilde ~).
But we have to do some extra computations:
Monad m => m (m b)
~ Functor f => ((c -> d) -> f d)
--------------------------------
m ~ (->) (c -> d), m b ~ f d
Hence we know that m is the same as (->) (c -> d) (basically this is a function where we know that input type, here (c -> d), and the output type is a type parameter of m.
So that means that m b ~ (c -> d) -> b ~ f d, so this means that f ~ (->) (c -> d) and b ~ d. An extra consequence is that since a ~ f c, we know that a ~ (c -> d) -> c
So to list what we derived:
f ~ m
m ~ (->) (c -> d)
b ~ d
a ~ (c -> d) -> c
So we now can "specialize" the types of both our lambda expression, and our flip fmap function:
(\x -> join . x)
:: (((c -> d) -> c) -> (c -> d) -> (c -> d) -> d) -> ((c -> d) -> c) -> (c -> d) -> d
flip fmap
:: ((c -> d) -> c) -> (c -> d) -> (c -> d) -> d
and type of flip fmap now perfectly matches with the type of the argument of the lambda expression. So the type of (\x -> join . x) (flip fmap) is the result type of the lambda expression type, and that is:
(\x -> join . x) (flip fmap)
:: ((c -> d) -> c) -> (c -> d) -> d
But now we of course did not yet obtained the implementation of this function. We are however already a step further.
Deriving the implementation
Since we now know that m ~ (->) (c -> d), we know we should lookup the arrow instance of a monad:
instance Monad ((->) r) where
f >>= k = \ r -> k (f r) r
So for a given function f :: r -> a, as left operand, and a function k :: a -> (r -> b) ~ a -> r -> b as operand, we construct a new function that maps a variable x to k applied to f applied to x, and x. It is thus a way to perform some sort of preprocessing on an input variable x, and then do the processing both taking into account the preprocessing and the original view (well this is an interpretation a human reader can use).
Now join :: Monad m => m (m a) -> m a is implemented as:
join :: Monad m => m (m a) -> m a
join x = x >>= id
So for the (->) r monad, this means that we implement this as:
-- specialized for `m ~ (->) a
join f = \r -> id (f r) r
Since id :: a -> a (the identity function) returns its argument, we can further simplify it to:
-- specialized for `m ~ (->) a
join f = \r -> (f r) r
or cleaner:
-- specialized for `m ~ (->) a
join f x = f x x
So it basically is given a function f, and will then apply an argument twice to that function.
Furthermore we know that the Functor instance for the arrow type is defined as:
instance Functor ((->) r) where
fmap = (.)
So it is basically used as a "post processor" on the result of the function: we construct a new function that will do the post processing with the given function.
So now that we specialized the function enough for the given Functor/Monad, we can derive the implementation as:
-- alternative implementation
h = (.) (\f x -> f x x) (flip (.))
or by using more lambda expressions:
h = \a -> (\f x -> f x x) ((flip (.)) a)
which we can now further specialize as:
h = \a -> (\f x -> f x x) ((\y z -> z . y) a)
-- apply a in the lambda expression
h = \a -> (\f x -> f x x) (\z -> z . a)
-- apply (\z -> z . a) in the first lambda expression
h = \a -> (\x -> (\z -> z . a) x x)
-- cleaning syntax
h a = (\x -> (\z -> z . a) x x)
-- cleaning syntax
h a x = (\z -> z . a) x x
-- apply lambda expression
h a x = (x . a) x
-- remove the (.) part
h a x = x (a x)
So h basically takes two arguments: a and x, it then performs function application with a as function and x as parameter, and the output is passed to the x function again.
Sample usage
As sample usage you use:
h (\f -> f u) (\x -> x + v)
or nicer:
h (\f -> f u) (+v)
so we can analyze this like:
h (\f -> f u) (+v)
-> (+v) ((\f -> f u) (+v))
-> (+v) ((+v) u)
-> (+v) (u+v)
-> ((u+v)+v)
So we add u+v to v.
Types line up easier with >>>:
a -> b >>>
b -> c ::
a -> c
Here, we have
join . flip fmap == flip fmap >>> join
flip fmap :: Functor f => f a -> ((a -> b) -> f b )
join :: Monad m => (m (m b)) -> m b
----------------------------------------------------------
flip fmap >>> join ::
(Functor f, Monad m) => f a -> m b , ((a -> b) ->) ~ m, f ~ m
::
(Functor f, Monad f) => f a -> f b , f ~ ((a -> b) ->)
:: ((a -> b) -> a) -> ((a -> b) -> b)
Simple, mechanical, mundane.
To see what it does, combinatory style definitions are usually easiest to twiddle with,
(join . flip fmap) f g x =
join (flip fmap f) g x = -- join f x = f x x
(`fmap` f) g g x = -- f `fmap` g = f . g
(g . f) g x
g (f g) x
So we don't need x after all (or do we?). The join and fmap definitions for functions are given in the margins. We've arrived at
(join . flip fmap) f g = g (f g) -- f :: (a -> b) -> a, g :: a -> b
-- f g :: a , g (f g) :: b
Another way is starting from the types, going by the rule of modus ponens,
((a -> b) -> a) (a -> b) -- f g
---------------------------
(a -> b) a -- g (f g)
---------------------------------------
b
I've got a function that's doing something currently working with particular datatypes. I was wondering if I could make it a general. Here's a generalised version of it's signature:
f :: Monad m => ((a -> b) -> c -> d) -> (a -> m b) -> m c -> m d
If the above can't be written, perhaps the more restricted version can?
f2 :: Monad m => ((a -> a) -> b -> b) -> (a -> m a) -> m b -> m b
No, it is impossible, at least without non-termination or unsafe operations.
The argument is essentially similar to this one: we exploit f to inhabit a type which we know can't be inhabited.
Assume there exists
f :: Monad m => ((a -> b) -> c -> d) -> (a -> m b) -> m c -> m d
Specialize c ~ ()
f :: Monad m => ((a -> b) -> () -> d) -> (a -> m b) -> m () -> m d
Hence
(\g h -> f (\x _ -> g x) h (return ()))
:: Monad m => ((a -> b) -> d) -> (a -> m b) -> m d
Speciazlize d ~ a.
(\g h -> f (\x _ -> g x) h (return ()))
:: Monad m => ((a -> b) -> a) -> (a -> m b) -> m a
Speclialize m ~ Cont t
(\g h -> runCont $ f (\x _ -> g x) (cont . h) (return ()))
:: ((a1 -> b) -> a) -> (a1 -> (b -> r) -> r) -> (a -> r) -> r
Take h = const
(\g -> runCont $ f (\x _ -> g x) (cont . const) (return ()))
:: ((r -> b) -> a) -> (a -> r) -> r
Hence
(\g -> runCont (f (\x _ -> g x) (cont . const) (return ())) id)
:: ((r -> b) -> r) -> r
So, the type ((r -> b) -> r) -> r is inhabited, hence by the Curry-Howard isomoprhism it corresponds to a theorem of propositional intuitionistic logic. However, the formula ((A -> B) -> A) -> A is Peirce's law which is known to be non provable in such logic.
We obtain a contradiction, hence there is no such f.
By contrast, the type
f2 :: Monad m => ((a -> a) -> b -> b) -> (a -> m a) -> m b -> m b
is inhabited by the term
f2 = \ g h x -> x
but I suspect this is not what you really want.
There's a problem. Knowing c doesn't give you any information about which as will be passed to (a -> b). You either need to be able to enumerate the universe of as or be able to inspect the provided a arguments with something like
(forall f. Functor f => ((a -> f b) -> c -> f d)
In which case it becomes almost trivial to implement f.
Instead of trying to implement f in general, you should try to generalize your functions like ((a -> b) -> c -> d) to see if you can replace them with lenses, traversals, or something similar.
According to the tutorial on Lenses:
type Getting b a b = (b -> Const b b) -> (a -> Const b a)
-- ... equivalent to: (b -> b ) -> (a -> b )
-- ... equivalent to: (a -> b )
Question: Why is (b -> b) -> (a -> b) equivalent to (a -> b)?
The tutorial isn't very precise about this. Here's the full definition of Getting:
type Getting r s a = (a -> Const r a) -> s -> Const r s
Stripping off the newtype noise,
Getting r s a ~= (a -> r) -> s -> r
The interesting isomorphism you should get from this is the following:
(forall r. Getting r s a) ~= s -> a
In a now-deleted comment, chi pointed out that this is a special case of the Yoneda lemma.
The isomorphism is witnessed by
fromGetting :: Getting a s a -> (s -> a)
fromGetting g = getConst . g Const
-- ~= g id
-- Note that the type of fromGetting is a harmless generalization of
-- fromGetting :: (forall r. Getting r s a) -> (s -> a)
toGetting :: (s -> a) -> Getting r s a
toGetting f g = Const . getConst . g . f
-- ~= g . f
-- Note that you can read the signature of toGetting as
-- toGetting :: (s -> a) -> (forall r. Getting r s a)
Neither fromGetting nor toGetting has a rank-2 type, but to describe the isomorphism, the forall is essential. Why is this an isomorphism?.
One side is easy: ignoring the Const noise,
fromGetting (toGetting f)
= toGetting f id
= id . f
= f
The other side is trickier.
toGetting (fromGetting f)
= toGetting (f id)
= \g -> toGetting (f id) g
= \g -> g . f id
Why is this equivalent to f? The forall is the key here:
f :: forall r. Getting r s a
-- forall r. (a -> r) -> s -> r
f has no way to produce an r except by applying the passed function (let's call it p) to a value of type a. It's given nothing but p and a value of type s. So f really can't do anything except extract an a from the s and apply p to the result. That is, f p must "factor" into the composition of two functions:
f p = p . h
So
g . f id = g . (id . h) = g . h = f g
The type says "You give me a b -> b and an a, and I'll give you a b." What can a function with that type do with its b -> b? Two options:
Ignore the function altogether
Apply it to a b
How do you get hold of a b to apply the function to? You use the a to produce one. So either way, it has to do the work of an a -> b.
Here's some code to witness the (edit: not-quite) isomorphism.
in :: ((b -> b) -> a -> b) -> (a -> b)
in f x = f id x
out :: (a -> b) -> ((b -> b) -> a -> b)
out f g x = g (f x)