Michał Wypych

Haskell Java Komentarz
data TypeConstructor = TypeConstructor String Int Int
public class TypeConstructor {
    public TypeConstructor(
                         String ?,
                         int ?,
                         int ?) {
        this.? = ?
        ...
    }
 
    private String ?;
    private int ?;
    private int ?;
}
Odpowiednikiem typu zadeklarowanego przez data jest klasa bez metod z jednym konstruktorem parametrycznym, w Haskellu można nie specyfikować nazw pól w typie stąd znaki zapytania w Javie
data Person = Person {name::String, phone::Int, age::Int}
p = Person "Maciek" 3941 25
macieksAge = age p
public class Person {
    public TypeConstructor(
                       String name,
                       int phone,
                       int age) {
        this.name = name
        ...
    }
 
    public String name(){
        return this.name;
    }
 
    public int phone() {
        return phone;
    }
 
    public int age() {
        return age;
    }
 
    private String name;
    private int phone;
    private int age;
}
Istnieje też wariant składni, w którym można wyspecyfikować nazwy pól, wtedy automatycznie tworzone są akcesory - funkcje o nazwie takiej jak nazwa pola.
data Box a = Box a String
public class Box<a> {
    public Box(a ?,String ?) {
        ...
    }
 
    private a ?;
    private String ?;
}
Typ sparametryzowany odpowiada mniej, więcej klasie generycznej z Javy, z tą różnicą, że Box String to inny typ niż Box Int, co w Javie nie ma zastosowania.
data Tree a 
          = Branch a (Tree a) (Tree a)
           | Leaf
public class Tree<a> {
 
}
 
public class Branch<a> extends Tree<a> {
    public Branch(a ?, Tree<a> ?, Tree<a> ?) {
        ...
    }
    private a ?;
    private Tree<a> ?;
    private Tree<a> ?;
}
 
public class Leaf<a> extends Tree<a> {
    public Leaf() {
 
    }
}
Dany typ w Haskellu może mieć kilka konstruktorów wartości, co można w Javie przedstawić za pomocą hierarchi dziedziczenia.
treeDepth :: Tree a -> Int
treeDepth (Branch _ ltree rtree) 
     = 1 + max (treeDepth ltree) (treeDepth rtree)
treeDepth Leaf = 0
public abstract class Tree ...
     abstract public int treeDepth();
 
 
public class Branch ... 
    public int treeDepth() {
        return 1 
           + max(ltree.treeDepth(),rtree.treeDepth());
    }
 
public class Leaf ...
    public int treeDepth() {
        return 0;
    }
warianty funkcji działającej w obrębie typu bazowego w Haskellu realizuje się przez pattern matching, natomiast w Javie tej konstrukcji odpowiada dziedziczenie po klasie abstrakcyjnej
class Show a where
    show::a->String
public interface Show {
    String show();
}
definicji klasy w Haskellu odpowiada Javowy interfejs. Natomiast w Haskellu klasy posiadają domyślne implementacje niektórych metod, coś co jest dopiero dostepne od Javy 8
instance Show Person where
    show (Person name phone age) = 
         "P {"++name++","++show phone
         ++","++show age++"}"
public class ShowablePerson implements Show {
    public ShowablePerson(Person person) {
        this.p = person;
    } 
    public String show() {
        return "P {"+p.getName()+...
    }
    private Person p;
}
 
public Person implements Show {
   public String show() {
        return "P {"+p.getName()+...
   }
}
przypisanie danego typu do klasy w Haskellu jest poprzedzone słowem kluczowym instance i może zostać zrealiozwane dla dowolnego nawet już instniejącego typu, stąd wydaje się, że lepszym odpowiednikiem w Javie jest stworzenie adaptera, który również można zastosować do typów bibliotecznych, których nie można modyfikować. Natomiast jeśli chodzi o użycie typu to druga wersja z bezpośrednią implementacją jest odpowiednikiem
cos::Show a => a -> String
public <a extends Show> String cos(a obj) {
...
}
Zawężenie typu przyjmowanego do typu należącego do danej klasy w Haskellu odpowiada specyfikacji funkcji generycznej w której typ dzidziczy/implementuje klasę/interface