Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a natural transformation in haskell?

Tags:

haskell

I would like to know, what is natural transformation in Haskell. The natural transformation is described with the following signature:

F[a] ~> G[a]

For example, I could transform:

Maybe a ~> List a

Right?

What about IO, it is impossible to do natural transformation right?
What is the purpose of the natural transformation?

like image 299
softshipper Avatar asked Oct 13 '19 13:10

softshipper


People also ask

What is meant by natural transformation?

In category theory, a branch of mathematics, a natural transformation provides a way of transforming one functor into another while respecting the internal structure (i.e., the composition of morphisms) of the categories involved. Hence, a natural transformation can be considered to be a "morphism of functors".

What makes an isomorphism natural?

A natural isomorphism from F to G is an isomorphism in the functor category Funct(C,D), that is, a natural transformation η:F→G for which there exists a natural transformation ξ:G→F such that the compositions ξ∘η=1F and η∘ξ=1G are identity natural transformations.


1 Answers

A natural transformation, without getting into the category theory behind it, is really just a polymorphic function.

Prelude> :set -XRankNTypes
Prelude> :set -XTypeOperators
Prelude> type (~>) f g = forall x. f x -> g x

The ~> operator maps a type constructor to another type constructor, in such a way that it works for any given argument to the first type constructor. The TypeOperator extension is what lets us use ~> instead of a name like NatTrans; the RankNTypes is what lets us use forall in the definition so that the caller can choose which type f and g will be applied to.

Here is an example of a natural transformation from Maybe to List, which takes a Maybe a for any type a, and produces an equivalent list (by returning either an empty list or the wrapped value as a singleton list).

Prelude> :{
Prelude| m2l :: Maybe ~> [] -- Maybe a -> [a]
Prelude| m2l Nothing = []
Prelude| m2l (Just x) = [x]
Prelude| :}
Prelude> m2l Nothing
[]
Prelude> m2l (Just 3)
[3]
Prelude> m2l (Just 'c')
"c"

An "inverse" would be l2m :: [] ~> Maybe, with l2m [] = Nothing and l2m (x:_) = Just x. ( I put inverse in quotes because m2l (l2m [1,2,3]) /= [1,2,3])

Nothing prevents you from using IO as either of the type constructors (although if IO is on the left, it must be on the right as well).

foo :: IO ~> IO
foo a = putStrLn "hi" >> a

Then

> foo (putStrLn "foo")
hi
foo
> foo (return 3)
hi
3

Another example would be to view length as a natural transformation from [] to Const Int (adapted from https://bartoszmilewski.com/2015/04/07/natural-transformations/, which I highly recommend reading):

-- Isomorphic to builtin length, as Const Int is isomorphic to Int
-- Requires importing Data.Functor.Const
length' :: [] ~> Const Int
length' [] = Const 0
length' (x:xs) = Const (1 + getConst (length' xs))
like image 199
chepner Avatar answered Dec 07 '22 05:12

chepner