Developer & Competency Manager
Norwegian JUG javaBin, Oslo Organizer
Who am I and why listen to me?
Oslo Software Architecture Co-Organizer
Java Champion
Writing as less code as possible is not a goal itself for the Java programming language.
Make it easier to build and maintain reliable code ... that's why people continue to use and trust Java.
- Brian Goezt
JEP-359 Records
JEP-360 Sealed Types
JEP-169 Value Types
JEP-305 Pattern Matching, instanceof
JEP-325 & 354 Switch Expressions
As other languages move towards functional style, Haskell get better tooling, libraries, stable releases, a growing community and increased industry adoption.
Haskell is constructed by expressions, not statements. Side-effects and mutation is hard, but is still possible. Haskell has tens of extensions called pragmas, that can be enabled.
Java src code
bytecode
machine code
JIT Compiler
Java Compiler
No optimization
JIT optimization
Haskell src code
Core code
machine code
STG code
HS Compiler
C - - code
C code
LLVM code
Low-level imperative language.
Optimisation
Parsing
Code-generation
Classloader
Java Class file
(Java Bytecode)
Execution
Engine
Native Method
Interface / Libraries
Heap
Stacks
Registers
Methods
STG-Program Code (machine code)
STG-machine
Executable binary file
Registers
Heap
Stacks
GHC Libraries
Haskell
Execution Context
(HEC)
Heap
Registers
*.java
JVM
*.hs
GHC
RTS
Separate pure and impure code as much as you can!
main = do
putStrLn "Write a line: "
line <- getLine
putStrLn $ "Input was: " ++ line
-- impure
main = do
putStrLn "Write a line: "
line <- getLine
putStrLn $ (append line)
-- pure
append :: String -> String
append input = "Input was: " ++ input
append is referentially transparent.
Sequencing (imperative style)
repl.it/@dervism/JavaLazyEval
double, long, int, float, char, short, byte, boolean, String
Int, Integer, Double, Float, Bool, Bits, Char, String
Primitives:
- Int#, Double#, Float#, Word#, Char#
Signed integrals:
- Int8, Int16, Int32, Int64
Haskell optimizes your code to use primitives (when possible).
Don't use Haskell's primitive types:
Int# causes eager evaluation!
Bits: Import Data.Bits, GHC.Prim + enable MagicHash extension.
int[] ints = new ints[6];
ints = array (0, 5) [(i, 0) | i <- [0..5]]
ints[5] = 10;
ints // [(5,10)]
int val = ints[5];
val = (ints ! 5)
new ints[] {1, 2, 3};
array (0,2) [(0,1), (1,2), (2,3)]
new ints[] {1, 2, 3};
listArray (0,2) [i+1 | i <- [0..2]]
listArray ('a','h') [i | i <- [0..8]]
Map<Character, Integer>
Haskell arrays are lazy and immutable.
Haskell provides mutable arrays
Haskell arrays are extremely flexible with enums.
Import Data.Array
This OR That.
This AND That
https://en.wikipedia.org/wiki/Tagged_union
Records, tuples, ADT (with one constructor), Java classes, C structs
https://en.wikipedia.org/wiki/Product_type
Java enums(*), ADTs (with several data constructors)
Also called: variant, choice type, discriminated union, disjoint union, coproduct
* cant extend with additional data
enum Animal {
DOG("Max"), CAT("Nala"),
ELK("Sam");
String name;
Animal(String name) {
this.name = name
}
}
data Animal = Dog | Cat | Elk
enum Animal {
DOG, CAT, ELK
}
data Animal = Dog String
| Cat String
| Elk String
name (Dog n) = n
name (Cat n) = n
name (Elk n) = n
data Animal = Dog String
| Cat String Int
| Elk Int Double | Unknown
info (Dog s) = "Name = " ++ s
info (Cat s i) = s ++ show i ++ " years."
info (Elk _ d) = "Elk weight" ++ show d
info _ = "Unknown animal"
enum AnimalType { Mammal, Bird, Fish }
record Animal(String name, int age, AnimalType type) {}
@Test
void propertiesEquals() {
var elephant = new Animal("Elephant", 10, Mammal);
assertEquals(elephant.name(), "Elephant");
assertEquals(elephant.age(), 10);
assertEquals(elephant.type(), Mammal);
}
https://github.com/dervism/java14-demo
data AnimalType = Mammal | Bird | Fish
deriving (Show)
data Animal = Animal {
name :: String,
age :: Int,
type :: AnimalType
}
instance Show Animal where
show (Animal a b c) = a ++ "," ++ show c
main = do
print $ (Animal "Elephant" 10 Mammal)
putStrLn $ name (Animal "Elephant" 10 Mammal)
-- Output: Elephant,Mammal
-- Output: Elephant
repl.it/@dervism/enumeration
https://chadaustin.me/2015/07/sum-types/
http://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt
sealed interface Node
permits A, B, C { ... }
data Spec = Spec {
engineType :: Engine,
maxSpeed :: Speed,
featureList :: [Feature]
}
data Transport = Car Spec
| Bus Spec | Plane Spec
class Automobile a where
spec :: a -> Spec
instance Automobile Transport where
spec (Car s) = s
spec (Bus s) = s
spec (Plane s) = s
With the exception of mutable types (such as MVars/TVars), all of Haskell's data types are first-class values.
inline class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() { return x; }
public int y() { return y; }
}
openjdk.java.net/jeps/169
cr.openjdk.java.net/~briangoetz/valhalla/sov/02-object-model.html
Spaces and tabs are ignored.
Indentation matters.
Braces and semicolons are required.
Braces and semicolons are optional.
public class MyClass {
public int add(int x, int y){
return x + y;
}
public String hello(){
return "Hello, world!";
}
}
module MyClass where
add :: Int -> Int -> Int
add x y = x + y
hello :: String
hello = "Hello, world!"
module MyClass where
add x y = x + y
hello = "Hello, world!"
import java.lang.*;
import java.util.Map;
import static
java.util.Arrays.sort;
public class MyClass {
...
}
import Prelude
import Data.Map
import qualified Data.Map as M
import Data.List (filter, sort)
import Data.List hiding (nub)
module MyClass where
...
module com.testmodule {
requires module.name;
requires static module.name;
requires transitive module.name;
exports package.name;
export package.name to some.package;
opens com.package;
opens com.package to anotherModule;
}
module ChessGame (
Result(..)
easy,
difficult,
run) where
run level = play level
easy = (Chess Normal)
difficult = (Chess Strong)
data Result = Won | Lost | Draw
data Ai = Normal | Strong
data Chess = Chess Ai
class Game a where
play :: a -> Result
instance Game Chess where
play chessAi = ....
module-info.java
public interface Person<A> {
String name(A a);
}
class Person a where
name :: a -> String
interface Person<A> {
String name(A a);
}
class Teacher {
String tName;
int tAge;
public Teacher(String tName, int tAge) {
this.tName = tName;
this.tAge = tAge;
}
}
class TeacherInstance implements Person<Teacher> {
@Override
public String name(Teacher teacher) {
return "Hello to " + teacher.tName;
}
}
class Student implements Person<Student> {
String sName;
int sAge;
public Student(String sName, int sAge) {
this.sName = sName;
this.sAge = sAge;
}
@Override
public String name(Student student) { // low cohesion
return "Hello to " + student.sName;
}
}
class Main {
public static void main(String[] args) {
TeacherInstance teacherInstance = new TeacherInstance();
System.out.println(teacherInstance.name(new Teacher("Jane", 30)));
Student student = new Student("Peter", 30);
System.out.println(student.name(student)); // ???
}
}
class Person a where
name :: a -> String
data Teacher = Teacher { tName :: String, tAge :: Int }
data Student = Student { sName :: String, sAge :: Int }
instance Person Teacher where
name teacher = "Hello to " ++ (tName teacher)
instance Person Student where
name student = "Hello to " ++ (sName student)
main = do
let teacher = name (Teacher "Jane" 30)
student = name (Student "Peter" 30)
putStrLn $ teacher ++ "\n" ++ student
repl.it/@dervism/JavaTypeclasses
repl.it/@dervism/typeclasses
interface Person {
String name();
}
class Teacher {
String tName;
int tAge;
public Teacher(String tName, int tAge) {
this.tName = tName;
this.tAge = tAge;
}
}
class TeacherInstance implements Person {
private Teacher teacher;
public TeacherInstance(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String name() {
return "Hello to " + teacher.tName;
}
}
class Student implements Person {
String sName;
int sAge;
public Student(String sName, int sAge) {
this.sName = sName;
this.sAge = sAge;
}
@Override
public String name() {
return "Hello to " + this.sName;
}
}
class Main {
public static void main(String[] args) {
TeacherInstance teacherInstance = new TeacherInstance(new Teacher("Jane", 30));
System.out.println(teacherInstance.name());
Student student = new Student("Peter", 30);
System.out.println(student.name());
}
}
data Person = Person {
salary :: Int,
taxClass :: TaxClass
}
if (salary > 900)
tax = salary * 0.44;
else
tax = salary * 0.36;
if salary > 900
then salary * 0.44
else salary * 0.36
if (salary > 900)
return salary * 0.44;
else if (salary > 500)
return salary * 0.36;
else
return salary * 0.24;
if salary > 900
then salary * 0.44
else if salary > 500
then salary * 0.36
else salary * 0.24
if salary > 900
then salary * 0.44
else if salary > 500
then salary * 0.36
else salary * 0.24
tax salary
| salary > 900 = salary * 0.44
| salary > 500 = salary * 0.36
| otherwise = salary * 0.24
tax salary
| salary > 900 = salary * 0.44
| salary > 500 = salary * 0.36
| otherwise = salary * 0.24
tax salary = salary * taxClass
where taxClass
| salary > 900 = 0.44
| salary > 500 = 0.36
| otherwise = 0.24
switch (taxClass) {
case CLASS_1:
return 0.44;
case CLASS_2:
return 0.36;
}
case taxClass of
CLASS_1 -> 0.44
CLASS_2 -> 0.36
switch (taxClass) {
case CLASS_1:
tax = 0.44;
break;
case CLASS_2:
tax = 0.36;
break;
}
enum Letter {A, B, C, D};
public String getLetter(Letter letter) {
return switch (letter) {
case A, B, C, D -> "A letter";
default -> "Unknown";
};
}
data Letter = A | B | C | D deriving (Enum, Eq)
letter :: Letter -> String
letter letter
| elem letter [A ..] = "A letter"
| otherwise = "Unknown"
@dervis_m
dervis.no
Thanks!
https://github.com/dervism
https://repl.it/@dervism
http://bit.ly/jfokus2020dm