A kept when or else-less chain over an Option arm is that Option, flattened one level, unless an Option of it is wanted.

This commit is contained in:
Joseph Ferano 2026-09-26 18:02:43 +07:00
parent b8e68a48f7
commit b814aca187
7 changed files with 153 additions and 50 deletions

View File

@ -49,6 +49,12 @@ found. Rules out =if let g = x= over a plain name, which is refused toward these
CLOSED: [2026-09-26] CLOSED: [2026-09-26]
Decided (138), like Swift: one level per boundary, the literal built at T first; not Decided (138), like Swift: one level per boundary, the literal built at T first; not
inside a container. Rules out implicit unwrapping: a T? where a T is wanted stays refused. inside a container. Rules out implicit unwrapping: a T? where a T is wanted stays refused.
** DONE A kept when over an Option body flattens one level
CLOSED: [2026-09-26]
Decided (140), reversing 125a: a kept =when=, else-less =if=/=elif= or =if let= chain whose
arm is already a =T?= is a =T?=, and =T= beside =T?= arms is =T?=; a =T??= arm stays =T??=.
Where =T??= is wanted the arm is Some of it. Rules out telling "no branch matched" apart
from "a branch gave None" without asking for =T??=.
** TODO The stepper does not step inside an optional chain ** TODO The stepper does not step inside an optional chain
=Ast.step_expr= treats a =Chain= as a leaf (its catch-all), so nothing in a chain's =Ast.step_expr= treats a =Chain= as a leaf (its catch-all), so nothing in a chain's
body gets a step point of its own. body gets a step point of its own.
@ -68,8 +74,8 @@ Option or a dyn holds (130); over any other type, and =_=, it is refused toward
** DONE when as a value, and get as a checked lookup ** DONE when as a value, and get as a checked lookup
CLOSED: [2026-09-26] CLOSED: [2026-09-26]
Every one-armed =if= (and a =cond= with no =:else=) is a =when=; kept — a =let= value, a Every one-armed =if= (and a =cond= with no =:else=) is a =when=; kept — a =let= value, a
call's argument, a lambda's return — it is =Option(T)=, nested over an Option body call's argument, a lambda's return — it is =Option(T)=, and body-or-nil where a dyn is
(Rust's =bool::then=), and body-or-nil where a dyn is wanted. A =_=-inferred return's wanted. Over an Option body it was nested (Rust's =bool::then=, 125a); 140 reversed that. A =_=-inferred return's
last form is not kept. =get= over dyn text or vec is nil when out of range; =.field= still traps. last form is not kept. =get= over dyn text or vec is nil when out of range; =.field= still traps.
** NEXT str and String ** NEXT str and String

View File

@ -8618,12 +8618,31 @@ and check_if_once ctx ~tail ~used ?want loc c t e =
| Some Types.Dyn -> Some Types.Dyn | Some Types.Dyn -> Some Types.Dyn
| _ -> None | _ -> None
in in
let t = branch ctx (fun () -> in_tail (fun () -> check ctx ?want:tw t)) in let arm w = branch ctx (fun () -> in_tail (fun () -> check ctx ?want:w t)) in
(* At an Option want the arm is asked the payload first, and the chain
wraps it; refused there, it is asked the Option itself, which it
then is (decision 140). So a T?? wanted of a T? arm is Some of it,
and the chain's own None stays the outer one. *)
let t, at_payload =
match want with
| Some (Types.Option _) ->
(match trial ctx (fun () -> arm tw) with
| Ok t -> t, true
| Error d ->
(match trial ctx (fun () -> arm want) with
| Ok t -> t, false
| Error _ -> raise (Loc.Error d)))
| _ -> arm tw, false
in
let rest ~used ?want () = let rest ~used ?want () =
branch ctx (fun () -> branch ctx (fun () ->
ctx.tail <- tail; ctx.used <- used; check ctx ?want e) ctx.tail <- tail; ctx.used <- used; check ctx ?want e)
in in
match t.Tast.ty with match t.Tast.ty with
| ty when at_payload && not (Types.equal ty Types.Never) ->
let oty = Option.get want in
let e = rest ~used:true ~want:oty () in
mk loc oty (Tast.If (c, mk loc oty (Tast.Some_ t), e))
| Types.Unit -> | Types.Unit ->
expect ctx loc ~want expect ctx loc ~want
(mk loc Types.Unit (Tast.If (c, t, rest ~used:false ()))) (mk loc Types.Unit (Tast.If (c, t, rest ~used:false ())))
@ -8633,32 +8652,14 @@ and check_if_once ctx ~tail ~used ?want loc c t e =
| Types.Dyn -> | Types.Dyn ->
let e = rest ~used:true ~want:Types.Dyn () in let e = rest ~used:true ~want:Types.Dyn () in
expect ctx loc ~want (mk loc Types.Dyn (Tast.If (c, t, e))) expect ctx loc ~want (mk loc Types.Dyn (Tast.If (c, t, e)))
(* An arm that is already an Option is the chain's value as it is,
and [None] when no test holds — one level flattened (decision
140): an arm's None and no arm running are one answer. *)
| Types.Option _ as o ->
let e = rest ~used:true ~want:o () in
expect ctx loc ~want (mk loc o (Tast.If (c, t, e)))
| ty -> | ty ->
let oty = Types.Option ty in let oty = Types.Option ty in
(* A later arm that is a T? where this one is a T: the arms meet at
T? (decision 138), so the chain is a T??, as it is when the T?
arm comes first. Tried only where the arm is refused at T. *)
let nested =
match want, ty with
| None, (Types.Option _ | Types.Unit) -> None
| None, _ ->
(match trial ctx (fun () -> rest ~used:true ~want:oty ()) with
| Ok e -> Some (Error e)
| Error _ ->
let ooty = Types.Option oty in
(match trial ctx (fun () -> rest ~used:true ~want:ooty ()) with
| Ok e -> Some (Ok e)
| Error _ -> None))
| _ -> None
in
match nested with
| Some (Ok e) ->
let ooty = Types.Option oty in
let t = mk loc ooty (Tast.Some_ (mk loc oty (Tast.Some_ t))) in
mk loc ooty (Tast.If (c, t, e))
| Some (Error e) ->
mk loc oty (Tast.If (c, mk loc oty (Tast.Some_ t), e))
| None ->
let e = rest ~used:true ~want:oty () in let e = rest ~used:true ~want:oty () in
expect ctx loc ~want expect ctx loc ~want
(mk loc oty (Tast.If (c, mk loc oty (Tast.Some_ t), e)))) (mk loc oty (Tast.If (c, mk loc oty (Tast.Some_ t), e))))
@ -8899,9 +8900,9 @@ and check_if_once ctx ~tail ~used ?want loc c t e =
branch evaluates to. Kept — a [let]'s value, an argument, a return, or branch evaluates to. Kept — a [let]'s value, an argument, a return, or
anything else with a type wanted of it — it answers (Option T): [Some] of anything else with a type wanted of it — it answers (Option T): [Some] of
the branch when the test held and [None] when it did not. A branch that the branch when the test held and [None] when it did not. A branch that
is already an Option is not flattened: the answer is (Option (Option T)), is already an Option is that Option, flattened one level (decision 140,
Rust's [bool::then], so [None] from the branch and a failed test stay two Kotlin's [?.] rather than Rust's [bool::then]): [None] from the branch and
answers. a failed test are one answer. A (Option (Option T)) branch stays one.
Dyn has no Option. Where a dyn is wanted, or the branch is a dyn, a false Dyn has no Option. Where a dyn is wanted, or the branch is a dyn, a false
test answers nil and a true one the branch's value — one absence, as a test answers nil and a true one the branch's value — one absence, as a
@ -8921,17 +8922,26 @@ and check_when ctx ~used ?want loc c
| Some Types.Dyn -> | Some Types.Dyn ->
let t = branch_at ~want:Types.Dyn () in let t = branch_at ~want:Types.Dyn () in
mk loc Types.Dyn (Tast.If (c, t, nil ())) mk loc Types.Dyn (Tast.If (c, t, nil ()))
| Some (Types.Option inner) -> | Some (Types.Option inner as oty) ->
let t = branch_at ~want:inner () in (* The payload first, wrapped; refused there, the Option itself, which
let oty = Types.Option inner in the branch then is (decision 140). *)
let some = if t.Tast.ty = Types.Never then t else mk loc oty (Tast.Some_ t) in let t =
mk loc oty (Tast.If (c, some, mk loc oty Tast.None_)) match trial ctx (fun () -> branch_at ~want:inner ()) with
| Ok t -> if t.Tast.ty = Types.Never then t else mk loc oty (Tast.Some_ t)
| Error d ->
(match trial ctx (fun () -> branch_at ~want:oty ()) with
| Ok t -> if t.Tast.ty = Types.Never then t else expect ctx loc ~want:(Some oty) t
| Error _ -> raise (Loc.Error d))
in
mk loc oty (Tast.If (c, t, mk loc oty Tast.None_))
| None when not used -> stmt (branch_at ()) | None when not used -> stmt (branch_at ())
| _ -> | _ ->
let t = branch_at () in let t = branch_at () in
if valueless t then stmt t if valueless t then stmt t
else if Types.equal t.Tast.ty Types.Dyn then else if Types.equal t.Tast.ty Types.Dyn then
expect ctx loc ~want (mk loc Types.Dyn (Tast.If (c, t, nil ()))) expect ctx loc ~want (mk loc Types.Dyn (Tast.If (c, t, nil ())))
else if (match t.Tast.ty with Types.Option _ -> true | _ -> false) then
expect ctx loc ~want (mk loc t.Tast.ty (Tast.If (c, t, mk loc t.Tast.ty Tast.None_)))
else else
let oty = Types.Option t.Tast.ty in let oty = Types.Option t.Tast.ty in
expect ctx loc ~want expect ctx loc ~want
@ -10021,7 +10031,7 @@ and check_array_gen ctx ~want loc dims f =
~element:(fun idxs -> mk loc elem (Tast.CallPtr (fv, idxs)))) ~element:(fun idxs -> mk loc elem (Tast.CallPtr (fv, idxs))))
and check_match ctx ?(tail = false) ?(used = false) ?(stmt = false) ?(opt = false) and check_match ctx ?(tail = false) ?(used = false) ?(stmt = false) ?(opt = false)
?opt_rest ?want loc scrutinee arms = ?(flat = false) ?opt_rest ?want loc scrutinee arms =
(* [stmt] is an [if let] with no else: a statement, Unit whatever its arm (* [stmt] is an [if let] with no else: a statement, Unit whatever its arm
answers, as a one-armed [if] is when nothing keeps it. [opt] is one that answers, as a one-armed [if] is when nothing keeps it. [opt] is one that
is kept: its arm answers [Some], and the arm with no body [None]. *) is kept: its arm answers [Some], and the arm with no body [None]. *)
@ -10030,7 +10040,11 @@ and check_match ctx ?(tail = false) ?(used = false) ?(stmt = false) ?(opt = fals
let want0 = want in let want0 = want in
let want = let want =
if stmt then None if stmt then None
else if opt then (match want with Some (Types.Option i) -> Some i | _ -> None) else if opt then
(match want with
| Some (Types.Option _) when flat -> want
| Some (Types.Option i) -> Some i
| _ -> None)
else want else want
in in
let s = check ctx scrutinee in let s = check ctx scrutinee in
@ -10629,6 +10643,14 @@ and check_match ctx ?(tail = false) ?(used = false) ?(stmt = false) ?(opt = fals
match r with match r with
| Some e -> e | Some e -> e
| None -> rt a.Ast.aloc Types.Dyn "flan_dyn_nil" []) | None -> rt a.Ast.aloc Types.Dyn "flan_dyn_nil" [])
(* Already an Option: the whole, one level flattened (decision 140). *)
| Some (Types.Option _ as o) when flat || want0 = None ->
opt_result := Some o;
let r = rest ~used:true ~want:o () in
fill Fun.id (fun a ->
match r with
| Some e -> e
| None -> mk a.Ast.aloc o Tast.None_)
| Some t -> | Some t ->
let oty = Types.Option t in let oty = Types.Option t in
opt_result := Some oty; opt_result := Some oty;
@ -10791,9 +10813,22 @@ and check_if_let ctx ~tail ~used ?want loc scrutinee (arm : Ast.arm) els =
ctx.tail <- tail; ctx.used <- used; check ctx ?want e)) ctx.tail <- tail; ctx.used <- used; check ctx ?want e))
els els
in in
(* The arm at the payload first, as [check_when] asks it; refused
there, at the Option itself (decision 140). *)
let go ~flat () =
check_match ctx ~tail ~used:true ~opt:true ~flat ?opt_rest ?want loc scrutinee
[ arm; wild [] ]
in
expect ctx loc ~want expect ctx loc ~want
(check_match ctx ~tail ~used:true ~opt:true ?opt_rest ?want loc scrutinee (match want with
[ arm; wild [] ])) | Some (Types.Option _) ->
(match trial ctx (go ~flat:false) with
| Ok r -> r
| Error d ->
(match trial ctx (go ~flat:true) with
| Ok r -> r
| Error _ -> raise (Loc.Error d)))
| _ -> go ~flat:false ()))
| Some e -> | Some e ->
check_match ctx ~tail ~used ?want loc scrutinee [ arm; wild [ e ] ] check_match ctx ~tail ~used ?want loc scrutinee [ arm; wild [ e ] ]
| None -> | None ->

View File

@ -252,7 +252,8 @@ Each item: the proposal, then the reason in one line.
into a `T??` is `Some` of it. A `$t` meeting `$u?` binds `$u` to `T`. into a `T??` is `Some` of it. A `$t` meeting `$u?` binds `$u` to `T`.
Never inside a container (`Vec(i32)` is not a `Vec(i32?)`), and never the Never inside a container (`Vec(i32)` is not a `Vec(i32?)`), and never the
other way: a `T?` where a `T` is wanted still needs `!`, `??`, `x?` or other way: a `T?` where a `T` is wanted still needs `!`, `??`, `x?` or
`as`. A kept chain whose arms are a `T` and a `T?` is a `T??`. **Built.** `as`. A kept chain whose arms are a `T` and a `T?` is a `T?` (decision
140, under `when c`). **Built.**
- **Casts and type-taking builtins are calls:** `i32(x)`, `vec-new(u8)`, - **Casts and type-taking builtins are calls:** `i32(x)`, `vec-new(u8)`,
`max-value(u8)`, `the([3 f32], [1 2 3.5])`. A pointer cast is the type `max-value(u8)`, `the([3 f32], [1 2 3.5])`. A pointer cast is the type
called: `Ptr(Color)(p)` reads `((Ptr Color) p)`. **Built.** called: `Ptr(Color)(p)` reads `((Ptr Color) p)`. **Built.**
@ -316,7 +317,13 @@ Each item: the proposal, then the reason in one line.
A `when` whose value is kept (a `let`'s value, an argument, a return) gives A `when` whose value is kept (a `let`'s value, an argument, a return) gives
`Some(a)` when `c` holds and `None` when it does not; where a `dyn` is `Some(a)` when `c` holds and `None` when it does not; where a `dyn` is
wanted, `a` or `nil`. As a statement it gives nothing. An `if`/`elif` chain wanted, `a` or `nil`. As a statement it gives nothing. An `if`/`elif` chain
with no `else` is the same when kept: `None` when no test holds. **Built.** with no `else` is the same when kept: `None` when no test holds. When `a`
is already an Option it is not wrapped again (decision 140): `when c then
o` over an `i32?` is an `i32?`, `None` when `c` fails or `o` is `None`, and
a chain mixing `T` and `T?` arms is a `T?`. One level only: an arm that is
a `T??` gives a `T??`. Where an Option of the arm's type is wanted, as a
`T??` over a `T?` arm, the arm is `Some` of its value and a failed test is
the outer `None`. `if let` with no `else` follows the same rule. **Built.**
- **`if let P = v`** plus a block reads as `(if-let [P v] then)`; `elif` and - **`if let P = v`** plus a block reads as `(if-let [P v] then)`; `elif` and
`else` follow as for `if`, the rest of the chain being the `if-let`'s else. `else` follow as for `if`, the rest of the chain being the `if-let`'s else.
`elif let P = v` is a further `if-let` nested in that else. `elif let P = v` is a further `if-let` nested in that else.

View File

@ -40,12 +40,24 @@ fn arms(k: i32, x: i32) -> i32?
fn big(x: i64?) -> i64 = x ?? 0 fn big(x: i64?) -> i64 = x ?? 0
;; A T?? is wanted, so each arm is Some of its value and the chain's None is
;; the outer one.
fn chain(a: bool, b: bool, opt: i32?) -> Option(i32?) fn chain(a: bool, b: bool, opt: i32?) -> Option(i32?)
if a if a
1 1
elif b elif b
opt opt
;; Nothing wanted: a T arm beside a T? arm makes the chain a T?, flattened
;; one level (decision 140).
fn flat(a: bool, b: bool, opt: i32?) -> i32?
let r =
if a
1
elif b
opt
r
fn main() fn main()
;; assignment, and a literal at the payload's width ;; assignment, and a literal at the payload's width
let s: i64? = None let s: i64? = None
@ -85,14 +97,15 @@ fn main()
let none: i32? = None let none: i32? = None
let nn2: Option(i32?) = none let nn2: Option(i32?) = none
println(two(nn), two(nn2)) println(two(nn), two(nn2))
;; a kept chain: a T arm beside a T? arm makes the chain a T?? ;; kept chains over T and T? arms
println(two(chain(true, false, none)), two(chain(false, true, none)), two(chain(false, false, none))) println(two(chain(true, false, none)), two(chain(false, true, none)), two(chain(false, false, none)))
println(flat(true, false, none) ?? -1, flat(false, true, Some(6)) ?? -1, flat(false, true, none) ?? -1, flat(false, false, none) ?? -1)
let kk = let kk =
if x > 9 if x > 9
none none
elif x > 1 elif x > 1
1 1
println(two(kk)) println(kk ?? -1)
;; generics ;; generics
println(first(9), first(Some(8)), wrap(3) ?? 0, through(5)) println(first(9), first(Some(8)), wrap(3) ?? 0, through(5))
;; a literal local takes the payload's type from an Option use, as it ;; a literal local takes the payload's type from an Option use, as it

View File

@ -21,6 +21,28 @@ fn early(a: Option(i32)) -> Option(i32)
elif true elif true
3 3
;; An arm that is already an Option is the whole, flattened (decision 140).
fn flat(a: Option(i32), o: Option(i32)) -> Option(i32)
if let Some(x) = a then o
;; An Option of it wanted: the arm is Some of its value, and no match is the
;; outer None.
fn nest(a: Option(i32), o: Option(i32)) -> Option(Option(i32))
if let Some(x) = a then o
fn level(oo: Option(Option(i32)))
match oo
Some(o) -> if o? then println(o) else println("some none")
None -> println("none")
fn flat_chain(a: Option(i32), k: i32)
let r =
if let Some(x) = a
x
elif k > 0
None
show(r)
fn dyn_only(a: Option(i32)) -> dyn fn dyn_only(a: Option(i32)) -> dyn
if let Some(x) = a then x if let Some(x) = a then x
@ -40,6 +62,15 @@ fn main()
show(lead(1, None)) show(lead(1, None))
show(early(None)) show(early(None))
show(early(Some(1))) show(early(Some(1)))
show(flat(Some(1), Some(4)))
show(flat(Some(1), None))
show(flat(None, Some(4)))
level(nest(Some(1), Some(4)))
level(nest(Some(1), None))
level(nest(None, Some(4)))
flat_chain(Some(3), 0)
flat_chain(None, 1)
flat_chain(None, 0)
println(dyn_only(Some(5))) println(dyn_only(Some(5)))
println(dyn_only(None)) println(dyn_only(None))
;; As a statement it is unchanged. ;; As a statement it is unchanged.

View File

@ -1,7 +1,8 @@
;;;; A when whose value is kept answers an Option: Some of its body when the ;;;; A when whose value is kept answers an Option: Some of its body when the
;;;; test holds, None when it does not. As a statement it answers nothing. ;;;; test holds, None when it does not. As a statement it answers nothing.
;;;; Where a dyn is wanted it answers the body or nil, since dyn has no ;;;; Where a dyn is wanted it answers the body or nil, since dyn has no
;;;; Option. A body that is already an Option is not flattened. ;;;; Option. A body that is already an Option is that Option, flattened one
;;;; level (decision 140), unless an Option of it is what is wanted.
(defn show [o (Option i32)] () (defn show [o (Option i32)] ()
(match o (Some v) (println v) None (println "none"))) (match o (Some v) (println v) None (println "none")))
@ -9,10 +10,13 @@
;; Returned: the return type is the want. ;; Returned: the return type is the want.
(defn half [n i32] (Option i32) (when (= 0 (% n 2)) (/ n 2))) (defn half [n i32] (Option i32) (when (= 0 (% n 2)) (/ n 2)))
;; Nested, as Rust's bool::then: None from the body stays apart from a ;; An (Option (Option i32)) is wanted, so the body is Some of it and the
;; failed test. ;; failed test is the outer None.
(defn wrap [c bool o (Option i32)] (Option (Option i32)) (when c o)) (defn wrap [c bool o (Option i32)] (Option (Option i32)) (when c o))
;; Flattened: None from the body and a failed test are one answer.
(defn flat [c bool o (Option i32)] (Option i32) (when c o))
(defn level [oo (Option (Option i32))] () (defn level [oo (Option (Option i32))] ()
(match oo (match oo
(Some o) (match o (Some v) (println v) None (println "some none")) (Some o) (match o (Some v) (println v) None (println "some none"))
@ -45,6 +49,12 @@
(level (wrap true (Some 1))) (level (wrap true (Some 1)))
(level (wrap true None)) (level (wrap true None))
(level (wrap false (Some 1))) (level (wrap false (Some 1)))
(show (flat true (Some 4)))
(show (flat true None))
(show (flat false (Some 4)))
(let [o (the (Option i32) (Some 8))
f (when true o)]
(show f))
(println (dyn-when true)) (println (dyn-when true))
(println (dyn-when nil)) (println (dyn-when nil))
(show (early None)) (show (early None))

View File

@ -2226,8 +2226,8 @@ let () =
dyn_if_truthy_out; dyn_if_truthy_out;
(* A kept when is an Option; get is a checked lookup; if let. *) (* A kept when is an Option; get is a checked lookup; if let. *)
let when_value_out = let when_value_out =
"5\nnone\n42\nnone\n9\n1\nsome none\nnone\n5\nnil\n3\nnone\n6\nnone\n20\nnone\n2\n\ "5\nnone\n42\nnone\n9\n1\nsome none\nnone\n4\nnone\nnone\n8\n5\nnil\n3\nnone\n6\nnone\n\
a\nnil\ncond stmt\nran\nend\n" 20\nnone\n2\na\nnil\ncond stmt\nran\nend\n"
in in
outputs "when as a value" "programs/when-value.flan" when_value_out; outputs "when as a value" "programs/when-value.flan" when_value_out;
outputs ~opt:"-O0" "when as a value, -O0" "programs/when-value.flan" when_value_out; outputs ~opt:"-O0" "when as a value, -O0" "programs/when-value.flan" when_value_out;
@ -2246,7 +2246,8 @@ let () =
"5\n100\n0\n9\n1\n20\n100\n0\n1\n7\nabsent\nnorth\n6\n-1\n-2\n14\nwhen block\n" "5\n100\n0\n9\n1\n20\n100\n0\n1\n7\nabsent\nnorth\n6\n-1\n-2\n14\nwhen block\n"
in in
let if_let_kept_out = let if_let_kept_out =
"1\n4\nnone\n6\nnone\n9\n2\nnone\n3\nnone\n5\nnil\n7\n" "1\n4\nnone\n6\nnone\n9\n2\nnone\n3\nnone\n4\nnone\nnone\n4\nsome none\nnone\n\
3\nnone\nnone\n5\nnil\n7\n"
in in
outputs "a kept if let chain" "programs/if-let-kept.fln" if_let_kept_out; outputs "a kept if let chain" "programs/if-let-kept.fln" if_let_kept_out;
outputs ~opt:"-O0" "a kept if let chain, -O0" "programs/if-let-kept.fln" if_let_kept_out; outputs ~opt:"-O0" "a kept if let chain, -O0" "programs/if-let-kept.fln" if_let_kept_out;
@ -2277,7 +2278,7 @@ let () =
(* A T where a T? is wanted is Some of it (decision 138). *) (* A T where a T? is wanted is Some of it (decision 138). *)
("autowrap.fln", ("autowrap.fln",
"-1\n5 4 2\n7 8 -1\n3 4\n7\n1 0 4\n5\n2 6 0\n2 -1 -1 2\n4\n-1 3 0\n\ "-1\n5 4 2\n7 8 -1\n3 4\n7\n1 0 4\n5\n2 6 0\n2 -1 -1 2\n4\n-1 3 0\n\
some some some none\nsome some some none none\nsome some\n9 8 3 5\n\ some some some none\nsome some some none none\n1 6 -1 -1\n1\n9 8 3 5\n\
4000000000 4000000000 4 4\n4 4000000000\n3.5 3.5 7 7\n200 200\n-1 5\n1 0\n10\n"); 4000000000 4000000000 4 4\n4 4000000000\n3.5 3.5 7 7\n200 200\n-1 5\n1 0\n10\n");
(* x? tests and narrows, e? as g names what it found (decision 133). *) (* x? tests and narrows, e? as g names what it found (decision 133). *)
("presence.fln", "true false true\n6\n-1\n3\n101 209 0\n11\n42\n2\nabsent\n6\nfalse true\n3\n6\n15\n"); ("presence-dyn.fln", "true false\n103 209 0\nno pet\nann\n3 2\n") ]; ("presence.fln", "true false true\n6\n-1\n3\n101 209 0\n11\n42\n2\nabsent\n6\nfalse true\n3\n6\n15\n"); ("presence-dyn.fln", "true false\n103 209 0\nno pet\nann\n3 2\n") ];