effekt
effekt copied to clipboard
Use information about previous pattern matches to optimize
For the following effekt code
import args
def join(left: Bool, right: Bool): Bool = (left, right) match {
case (true, true) => true
case (false, _) => false
case (_ , false) => false
}
def main() = commandLineArgs() match {
case Cons(input, _) => println(join(input == "a", input == "b"))
case Nil() => ()
}
our pattern matching compiler currently generates
switch (v_r_0.__tag) {
case 1:
const input_0 = v_r_0.head_0;
const tmp_3 = input_0 === "a";
const tmp_4 = input_0 === "b";
if (tmp_3) if (tmp_4) {
const tmp_5 = $effekt.println("true");
return () => k_1(tmp_5, ks_2);
} else if (tmp_4) {
return $effekt.hole(); // UNREACHABLE
} else {
const tmp_6 = $effekt.println("false");
return () => k_1(tmp_6, ks_2);
} else if (tmp_3) {
return $effekt.hole(); // UNREACHABLE
} else {
const tmp_7 = $effekt.println("false");
return () => k_1(tmp_7, ks_2);
}
break;
case 0: return () => k_1($effekt.unit, ks_2);
}
where I marked the two holes as unreachable. We seem to lose the positive information about scrutinees (maybe look at Sestoft's paper again?)
Ideally, in this case we would generate
if (tmp_3) {
if (tmp_4) {
const tmp_5 = $effekt.println("true");
return () => k_1(tmp_5, ks_2);
} else {
const tmp_6 = $effekt.println("false");
return () => k_1(tmp_6, ks_2);
}
} else {
const tmp_7 = $effekt.println("false");
return () => k_1(tmp_7, ks_2);
}
In case it helps anybody else, here's the [lightly edited] Core repr. of join:
def join_3621(left_3619: Bool_379, right_3620: Bool_379) = {
let v_r_3797 = make Tuple2_253[Bool_379, Bool_379] Tuple2_311(left_3619, right_3620)
val v_r_3801: Bool_379 = v_r_3797 match {
case Tuple2_311 { (first_3659: Bool_379, second_3658: Bool_379) =>
if (first_3659) {
if (second_3658) {
return true
} else {
if (second_3658) {
<> // UNREACHABLE
} else {
return false
}
}
} else {
if (first_3659) {
<> // UNREACHABLE
} else {
return false
}
}
}
};
return v_r_3801
};
FWIW, if I do the following (which might be wrong):
case Some(values) =>
if values.exists(b => !variants.map(_.value).contains(b)) then
addDefault(c)
- variants.foreach { v => addClause(v, c) }
+ variants.foreach { v => addClause(v, c) }
then the output becomes a tad better, but wrong :(
val v_r_3801: Bool_379 = v_r_3797 match {
case Tuple2_311 { (first_3659: Bool_379, second_3658: Bool_379) =>
if (first_3659) {
if (second_3658) {
b_k0_3798()
} else {
<>
}
} else {
if (first_3659) {
<>
} else {
b_k1_3799()
}
}
}
};
@jiribenes don't worry about it too much, I think I know what to do ;)