Tuesday, 11 December 2018

Hylomorphism in 1 minute

Hylomorphism is  Catamorphism compose to Anamorphism function.

It's presented as 

Hylomorphism = catamorphism(anamorphism(x))
 or
Hylomorphism = fold(unfold(x))

Basically it constructs (unfold) complex type (like trees, lists) and destructs (folds) back into representing value.

For example to get factorial from N we can 
a) unfold N to list of (n),(n-1),..,0
b) fold with prod function the list from previous step.

And possible Scala example implementing function for getting factorial from N with help of previously introduced list's Catamorphism and  Anamorphism is:
type ListHylomorphism[U] = U => U
def listHylomorphism[U, T](cata: ListCatamorphism[T, U], ana: ListAnamorphism[U, T]): ListHylomorphism[U] = cata.compose(ana)
val factorial = listHylomorphism(prod, listDestruct)
assert(factorial(3) == 6)

Anamorphism in 1 minute


An Anamorphism (from the Greek ἀνά "upwards" and μορφή "form, shape) over a type T is a function of type U → T that destructs the U in some way into a number of components. On the components that are of type U, it applies recursion to convert theme to T 's. After that it combines the recursive results with the other components to a T , by means of the constructor functions of T .

For example if we want to build List(N, N-1, …, 1) from N we would use anamorphism from Int to List[Int]. It’s the opposite operation to fold - unfold.
type ListAnamorphism[U, T] = U => List[T]
def listAnamorphismFactory[U, T](func: T => Option[(U, T)]): ListAnamorphism[T, U] = {
in: T =>
def ana(initial: T): List[U] = func(initial) match {
case None => Nil
case Some((current, next)) => current :: ana(next)
}
ana(in)
}
val listDestruct: ListAnamorphism[Int, Int] = listAnamorphismFactory { i: Int => if (i == 0) None else Some(i, i - 1) }


Catamorphism in 2 minutes


Catamorphism (κατά "downwards" and μορφή "form, shape") on a type T is a function of type T → U that destruct and object of type T according to the structure of T, calls itself recursively of any components of T that are also of type T and combines this recursive result with the remaining components of T to a U.

And it's just an official name of fold/reduce on higher kinded types. 

For example getting the prod from list of integers is Catamorphism on the list:

def prod(list: List[Int]): Int = list match {
case Nil => 1
case head :: tail => head * prod(tail)
}
view raw cata.scala hosted with ❤ by GitHub

Catamorphism in programming can be used to fold complex structures (lists, tress, sets)  into their representation via different type. As an example list catamorphism can be described as

type ListCatamorphism[T, U] = List[T] => U
def listCatamorphism[T, U](value: U, func: (T, U) => U): ListCatamorphism[T, U] = {
def cata(list: List[T]): U = {
list match {
case Nil => value
case head :: tail => func(head, cata(tail))
}
}
cata
}
view raw listCata.scala hosted with ❤ by GitHub

And if we want to fold the list into prod from elements we would use:
def prod: List[Int] => Int = listCatamorphism[Int, Int](1, _ * _)
view raw prod.scala hosted with ❤ by GitHub


Tuesday, 4 December 2018

Isomorphism in 3 minutes



An Isomorphism (from the Ancient Greek: ἴσος isos "equal", and μορφή morphe "form" or "shape") is a homomorphism or morphism (i.e. a mathematical mapping) that can be reversed by an inverse morphism. Two mathematical objects are isomorphic if an isomorphism exists between them.
Isomorphism between the types means that we can convert T  →  U and then U → T lossless.

For example Int to String conversion is sort of isomorphism, but not all the possible values of String can be converted to Int. For example when we try to convert “Assa” into Int we get an Exception. If we want to use identity element for example 0 for any non-number String - Int2String won’t be Isomorphic anymore.

abstract class Iso[T, U] {
def get(t: T): U
def reverseGet(u: U): T
}
class Int2String extends Iso[Int, String] {
override def get(t: Int): String = t.toString
override def reverseGet(u: String): Int = u.toInt
}
view raw isom.scala hosted with ❤ by GitHub

The real isomorphic mapping from String to Int can be done via co-algebra (list’s co-algebra):

class EitherInt2String extends Iso[Either[String, Int], String] {
override def get(t: Either[String, Int]): String = t match {
case Left(l) => l
case Right(r) => r.toString
}
override def reverseGet(u: String): Either[String, Int] = {
Try(u.toInt).toEither.left.map(_ => u)
}
}
view raw realIso.scala hosted with ❤ by GitHub

You’ve probably generated the tons of Unit tests for  JSON → String and String → JSON isomorphism prove.

Singleton types are always isomorphic to itself, for example type Unit has only one set’s member Unit or () and it’s always isomorphic to itself. Scala compiler has a special flag -Ywarn-value-discard that checks method returns type may break isomorphism rule (make sense only for non side-effect calls).

/**
* -Ywarn-value-discard
*/
def intFunction(): Unit = {
3
}
def stringFunction(): Unit = {
"3"
}
// Despite return types functions aren't isomorphic
assert(intFunction() == stringFunction())


Currying functions are isomorphic to each other:
val sum: (Int, Int) => Int = _ + _
val curried: Int => Int => Int = sum.curried
def sumIsIso(a: Int, b: Int) = {
assert(sum(a, b) == curried(a)(b))
assert(sum(a, b) == Function.uncurried(curried)(a, b))
}
view raw curry.scala hosted with ❤ by GitHub

Function1 in Scala doesn’t have the curry method and that is why curry isn’t isomorphic for all the Scala’s functions - but it could be if curry from Function1 returned Function1[T, Function1[T1, U]].


Isomorphism as applied to web development means been able to render pages on the both server and client sides. It’s used in context of NodeJS ecosystem because of been able to reuse libraries/frameworks in backend and frontend.