What is the Java equivalent of this Haskell function?
Edit: a workaround to failures in this kind of cases is the use of the Maybe Monad
, and his cousin in Java is the Optional
class, where Option.of
would be return
and flatMap
would be bind
. On the other hand in Java and others O.O. languages there is a common pattern to use in this kind of cases called composite, basically your data type Expr
will be an interface or abstract class, and the type constructors will be the leaves:
So, with all of that in mind, a simple example working would be:
In haskell:
data Expr = Val Int | Div Expr Expr
eval :: Expr -> Maybe Int
eval (Val n) = Just n
eval (Div x y) = do
v1 <- eval x
v2 <- eval y
if v2 == 0
then Nothing
else return (div v1 v2)
n1 = Val 8
n2 = Val 4
n3 = Val 0
d1 = Div n1 n2
d2 = Div d1 d1
d3 = Div d2 n3
main = do
putStrLn $ show (eval d2)
putStrLn $ show (eval d3)
Equivalent approach in Java:
import java.util.Optional;
public interface Expr {
public Optional<Integer> eval();
}
Then the leaves implementing Expr:
import java.util.Optional;
public class Val implements Expr{
Optional<Integer> value;
public Val(int value) {
this.value = Optional.of(value);
}
@Override
public Optional<Integer> eval() {
return value;
}
}
Then the recursive case:
import java.util.Optional;
public class Div implements Expr {
Expr expr1;
Expr expr2;
public Div(Expr expr1, Expr expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public Optional<Integer> eval() {
return expr1.eval().flatMap(v1 ->
expr2.eval().flatMap(v2 ->
(v2 == 0) ? Optional.empty() : Optional.of(v1 / v2)
)
);
}
public static void main(String[] args) {
Expr iv1 = new Val(6);
Expr iv2 = new Val(3);
Expr iv3 = new Val(2);
Expr iv4 = new Val(0);
Expr div1 = new Div(iv1, iv2);
Expr div2 = new Div(div1, iv3);
Expr div3 = new Div(div2, iv4);
System.out.println(div2.eval());
System.out.println(div3.eval());
}
}
The main function output will be:
Optional[1]
Optional.empty
Other answers have covered a more idiomatic way of implementing this in Java, and described how to use Optional
to handle errors. But here I’d like to give the direct equivalent of Haskell pattern matching in Java, with the visitor pattern:
public class ExprTest {
public static void main(String[] arguments) {
// expr :: Expr
// expr = Div
// (Div
// (Div (Val 100) (Val 5))
// (Val 2))
// (Div (Val 10) (Val 2))
Expr two = new Val(2);
Expr twenty = new Div(new Val(100), new Val(5));
Expr ten = new Div(twenty, new Val(2));
Expr five = new Div(new Val(10), two);
Expr expr = new Div(ten, five);
// eval :: Expr -> Int
// eval expr = case expr of
ExprVisitor<Integer> eval = new ExprVisitor<Integer>() {
// Val value -> value
public Integer visit(Val val) {
return val.value;
}
// Div left right -> eval left `div` eval right
public Integer visit(Div div) {
return div.left.match(this) / div.right.match(this);
}
};
// main = print (eval expr)
System.out.println(expr.match(eval));
}
}
// data Expr
abstract class Expr {
abstract <T> T match(ExprVisitor<T> visitor);
}
// = Val Int
class Val extends Expr {
public final int value;
public Val(int value) {
this.value = value;
}
<T> T match(ExprVisitor<T> visitor) {
return visitor.visit(this);
}
}
// | Div Expr Expr
class Div extends Expr {
public final Expr left, right;
public Div(Expr left, Expr right) {
this.left = left;
this.right = right;
}
<T> T match(ExprVisitor<T> visitor) {
return visitor.visit(this);
}
}
abstract class ExprVisitor<T> {
abstract T visit(Val val);
abstract T visit(Div div);
}
In the land of functional programming, this is called Böhm–Berarducci encoding—sometimes referred to as Church encoding, although they’re different things. This is a fancy-sounding way of saying “representing data types and pattern matching with functions”. You can of course use this encoding of matching in Haskell:
match
:: (Int -> t) -- visit(Val)
-> (Expr -> Expr -> t) -- visit(Div)
-> Expr
-> t
match val div expr = case expr of
Val x -> val x
Div left right -> div left right
eval :: Expr -> Int
eval = match id (\ left right -> eval left `div` eval right)
Since eval
is recursive, you can also write it using the fixed point combinator fix
—and then the use of this
in the ExprVisitor
in the Java version may become more clear: it’s how you make eval
recursive!
import Data.Function (fix)
eval :: Expr -> Int
eval = fix $ \ this -> match
(\ value -> value)
(\ left right -> this left `div` this right)
And here’s the other half of the encoding: we can do away with the data type altogether and just use functions:
{-# LANGUAGE RankNTypes #-}
newtype Expr = Expr
{ visit
:: forall a.
(Int -> a) -- Val
-> (a -> a -> a) -- Div
-> a }
valE :: Int -> Expr
valE x = Expr $ \ v _d -> v x
divE :: Expr -> Expr -> Expr
divE left right = Expr $ \ v d
-> d (visit left v d) (visit right v d)
eval :: Expr -> Int
eval expr = visit expr
(\ val -> val)
(\ left right -> left `div` right)
eval (divE
(divE (divE (valE 100) (valE 5)) (valE 2))
(divE (valE 10) (valE 2)))
== 2
And that implementation of eval
can of course be written as just this:
eval = visit expr id div
You could evaluate both x
and y
before the division:
Integer xE = x.evaluate(), yE = y.evaluate();
And then see if yE
is equal to 0
:
if(yE == 0){
// your logic here if it is a division by 0
}
Which would yield you with the following function:
public Integer evaluate() {
Integer xE = x.evaluate(), yE = y.evaluate();
if(yE == 0){
// your logic here if it is a division by 0
}
return xE / yE;
}