Hi,
I have used a very simple effect handler before and I thought this code is even simpler. But I see an error I don’t understand. Here the effect handler is ignored. I may take some action or not but I intend to leave the fold.
The fold iterates over a list of records.
List.fold returns an int but an expressions is expected of type int → unit
type _ Effect.t += Plass_break : int -> unit Effect.t
let rec plassbreak idx idealwidth maxwidth ?(indent = 0) =
let
lastrecord = List.nth !l idx in
let llen = ref (lastrecord.last - lastrecord.first) in
let bscore = idealwidth - !llen in
let bscore = ref (bscore * 2) in
let btail = ref (idx + 1) in
List.fold_left (fun (acc: int) entry ->
match entry with
| {first; last; next; score} ->
let wwidth = last - first in
if ((!llen + wwidth) >= maxwidth) then(
perform (Plass_break acc);
acc
)else(
let lscore = ref (idealwidth - (!llen + wwidth)) in
lscore := !lscore * 2;
llen := !llen + wwidth + 1;
if score == -1 then
plassbreak (acc + 1) idealwidth maxwidth (indent + 1);
let
record = List.nth !l acc in
if ((!lscore + score) < !bscore) then(
bscore := !lscore + record.score;
btail := acc + 1;
);
if score = !bscore then (
let updated_record = { record with next = !btail } in
ignore updated_record;
);
if (record.next + 1) = List.length !l then (
let updated_record = { record with score = 0 } in
ignore updated_record;
);
acc + 1
)
) 0 !l
This code compiles but is untested. I use ‘refs’ and probably some approaches that are not functional. Is the ‘effect handler’ the problem as it is not handled ?
I also use ‘ignore’ at the end when I update records.
Thanks,
Mohan
Could you specify what do you mean by “the effect handler is ignored”? There’s certainly a lot of context missing to understand your snippet, but as far as effects are concerned I see a call to perform
(I’m assuming this is bound to Effect.perform
), but not any actual handlers.
If the caller to plassbreak
is actually wrapping the call with an effect handler, and you’re sure it isn’t triggering, then I’d assume the condition guarding the call to perform
is always false in your tests.
Not sure if you’re aware and this is just a sketch, but that syntax makes an updated copy, so by ignoring them you aren’t updating them. If those are mutable fields, use record.field <- new_value
.
As a side note, I’m also a bit suspicious of that optional ?(indent = 0)
as the last parameter instead of first, where it isn’t really optional: a call like plassbreak 0 60 80
won’t evaluate the function but return an intermediate ?indent:int -> int
, which can be easy to miss on the toplevel/REPL.
I meant that I could choose to continue or not when the effect handler fires but I have to understand and test it.
Just guessed that the optional parameter could cause this.
Refactored the code based on this discussion. This is a compilation error caused by the optional parameter ? I couldn’t understand the original compiler error at all. How ?
Now it does compile.
The effect handler was a red herring ? Guessing I can handle it the usual way.
let rec plassbreak indent idx idealwidth maxwidth =
let
lastrecord = List.nth !l idx in
let llen = ref (lastrecord.last - lastrecord.first) in
let bscore = idealwidth - !llen in
let bscore = ref (bscore * 2) in
let btail = ref (idx + 1) in
let _ =
List.fold_left (fun acc entry ->
match entry with
| {first; last; next; score} ->
let wwidth = last - first in
if ((!llen + wwidth) >= maxwidth) then(
perform (Plass_break acc);
acc
)else(
let lscore = ref (idealwidth - (!llen + wwidth)) in
lscore := !lscore * 2;
llen := !llen + wwidth + 1;
if score == -1 then
plassbreak (indent + 1) (acc + 1) idealwidth maxwidth;
let
record = List.nth !l acc in
if ((!lscore + score) < !bscore) then(
bscore := !lscore + record.score;
btail := acc;
);
acc + 1;
)
) idx !l in
let record = List.nth !l idx in
record.next <- !btail;
record.score <- !bscore;
if (record.next + 1) = List.length !l then (
record.score <- 0;
);
Primarily the recursion didn’t compile until I removed the optional parameter.
Thanks.