Skip to content

Commit d12fa79

Browse files
dbrattliclaude
andcommitted
[Python/Beam] Align random* error messages with .NET and fix pyright errors
Review follow-ups for #4488: Python: - Delete orphaned fable-library-py/fable_library/Array.fs (not in fsproj, declared module ArrayModule, never compiled). - Replace bare PyException("argname") raises in Rust extension with PyValueError carrying descriptive messages aligned with dotnet/fsharp FSharp.Core resource strings. Randomizer validation now matches .NET's dynamic format exactly, including the actual returned value. - Fix core/array.pyi: change Callable[[], float] -> Callable[[], SupportsFloat] for all 15 random *_by signatures. Fable transpiles F# (fun () -> 0.0) as returning Float64, which caused 13 pyright errors in test_array.py. Beam: - Align randomizer error message with .NET's dynamic format via io_lib:format. - Use andalso in random_sample_by guard (idiomatic Erlang). - Refactor random_choices_by: drop lists:map + lists:seq + lists:nth O(n) per-pick and use a tail-recursive choices_loop/5 helper with list_to_tuple for O(1) indexed access, matching the pattern used by shuffle_loop and sample_loop in the same file. Verification: - cargo check fable-library-core: clean - ./build.sh test python: 2233 passed, 0 failed - pyright on temp/tests/Python/: 0 errors (was 13) - ./build.sh test beam: 2390 passed, 0 failed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e870773 commit d12fa79

4 files changed

Lines changed: 67 additions & 1388 deletions

File tree

src/fable-library-beam/fable_list.erl

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ random_choice_by(Randomizer, Xs) ->
639639
R = Randomizer(ok),
640640
if
641641
R < 0.0; R >= 1.0 ->
642-
erlang:error(<<"The randomizer function should return a float in [0, 1).">>);
642+
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
643643
true ->
644644
lists:nth(erlang:trunc(R * Len) + 1, Xs)
645645
end.
@@ -657,25 +657,25 @@ random_choices_by(Randomizer, Count, Xs) ->
657657
if
658658
Count < 0 ->
659659
erlang:error(<<"The input must be non-negative.">>);
660+
Count > 0 andalso Xs =:= [] ->
661+
erlang:error(<<"The input sequence was empty.">>);
660662
true ->
661-
case {Count > 0, Xs} of
662-
{true, []} ->
663-
erlang:error(<<"The input sequence was empty.">>);
664-
_ ->
665-
Len = erlang:length(Xs),
666-
lists:map(
667-
fun(_) ->
668-
R = Randomizer(ok),
669-
if
670-
R < 0.0; R >= 1.0 ->
671-
erlang:error(<<"The randomizer function should return a float in [0, 1).">>);
672-
true ->
673-
lists:nth(erlang:trunc(R * Len) + 1, Xs)
674-
end
675-
end,
676-
lists:seq(1, Count)
677-
)
678-
end
663+
Arr = erlang:list_to_tuple(Xs),
664+
Len = erlang:tuple_size(Arr),
665+
choices_loop(Randomizer, Arr, Len, Count, [])
666+
end.
667+
668+
%% Tail-recursive helper for random_choices_by: builds result in reverse then flips.
669+
choices_loop(_Randomizer, _Arr, _Len, 0, Acc) ->
670+
lists:reverse(Acc);
671+
choices_loop(Randomizer, Arr, Len, N, Acc) ->
672+
R = Randomizer(ok),
673+
if
674+
R < 0.0; R >= 1.0 ->
675+
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
676+
true ->
677+
E = erlang:element(erlang:trunc(R * Len) + 1, Arr),
678+
choices_loop(Randomizer, Arr, Len, N - 1, [E | Acc])
679679
end.
680680

681681
-spec random_choices_with(ok, non_neg_integer(), list()) -> list().
@@ -694,7 +694,7 @@ random_sample_by(Randomizer, Count, Xs) ->
694694
true ->
695695
Len = erlang:length(Xs),
696696
if
697-
Len =:= 0, Count > 0 ->
697+
Len =:= 0 andalso Count > 0 ->
698698
erlang:error(<<"The input sequence was empty.">>);
699699
Count > Len ->
700700
erlang:error(<<"The input sequence has an insufficient number of elements.">>);
@@ -718,7 +718,7 @@ sample_loop(Randomizer, Arr, Len, Count, I) ->
718718
R = Randomizer(ok),
719719
if
720720
R < 0.0; R >= 1.0 ->
721-
erlang:error(<<"The randomizer function should return a float in [0, 1).">>);
721+
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
722722
true ->
723723
J = I + erlang:trunc(R * (Len - I)),
724724
EI = erlang:element(I + 1, Arr),
@@ -734,7 +734,7 @@ shuffle_loop(Randomizer, Arr, I) ->
734734
R = Randomizer(ok),
735735
if
736736
R < 0.0; R >= 1.0 ->
737-
erlang:error(<<"The randomizer function should return a float in [0, 1).">>);
737+
erlang:error(iolist_to_binary(io_lib:format("The index is outside the legal range.~nrandomizer returned ~w, should be in range [0.0, 1.0).", [R])));
738738
true ->
739739
J = erlang:trunc(R * (I + 1)),
740740
EI = erlang:element(I + 1, Arr),

0 commit comments

Comments
 (0)