diff --git a/changelog.d/20260713_144500_fromstring_fn4.md b/changelog.d/20260713_144500_fromstring_fn4.md new file mode 100644 index 0000000..0e5235a --- /dev/null +++ b/changelog.d/20260713_144500_fromstring_fn4.md @@ -0,0 +1,7 @@ +### Fixed + +- `fromStringImpl` matches its `Fn4` declaration: the Lua entry is a single + 4-ary function (previously it was a chain of nested single-argument + closures, so `Data.Number.fromString` returned a function instead of a + `Maybe Number` — Lua silently drops the surplus arguments of the n-ary + `runFn4` call). diff --git a/src/Data/Number.lua b/src/Data/Number.lua index 5242d3c..fc922ff 100644 --- a/src/Data/Number.lua +++ b/src/Data/Number.lua @@ -42,20 +42,15 @@ return { sqrt = (math.sqrt), tan = (math.tan), trunc = (function(x) return x < 0 and math.ceil(x) or math.floor(x) end), - fromStringImpl = (function(str) - return function(isFinite) - return function(just) - return function(nothing) - -- Mirror JS parseFloat: a leading-numeric prefix is parsed and - -- trailing junk (and a whitespace prefix) is tolerated. Guard against - -- a failed parse — the old code wrapped tonumber's nil in Just — and - -- use the supplied isFinite predicate so non-finite results are Nothing. - local prefix = str:match("^%s*([%-+]?%d*%.?%d+[eE]?[%-+]?%d*)") - local x = prefix and tonumber(prefix) or nil - if x ~= nil and isFinite(x) then return just(x) end - return nothing - end - end - end + fromStringImpl = (function(str, isFinite, just, nothing) + -- Declared Fn4, so the entry is a single 4-ary function. + -- Mirror JS parseFloat: a leading-numeric prefix is parsed and + -- trailing junk (and a whitespace prefix) is tolerated. Guard against + -- a failed parse — the old code wrapped tonumber's nil in Just — and + -- use the supplied isFinite predicate so non-finite results are Nothing. + local prefix = str:match("^%s*([%-+]?%d*%.?%d+[eE]?[%-+]?%d*)") + local x = prefix and tonumber(prefix) or nil + if x ~= nil and isFinite(x) then return just(x) end + return nothing end) } diff --git a/test/regression/number.lua b/test/regression/number.lua index d118ca9..9a6d688 100644 --- a/test/regression/number.lua +++ b/test/regression/number.lua @@ -50,10 +50,12 @@ check("min 1 NaN is NaN", isNaN(M.min(1)(nan)), tostring(M.min(1)(nan))) check("min NaN 1 is NaN", isNaN(M.min(nan)(1)), tostring(M.min(nan)(1))) check("min 3 7 == 3", M.min(3)(7) == 3, tostring(M.min(3)(7))) --- #93 fromString (via the Fn4-style curried FFI) +-- #93 fromString. fromStringImpl is declared `Fn4`, so the Lua entry is a +-- 4-ary function called with all arguments at once (`runFn4` and the +-- compiler's uncurried lift both call it that way). local function just(x) return {tag = "just", value = x} end local nothing = {tag = "nothing"} -local function fromString(s) return M.fromStringImpl(s)(M.isFinite)(just)(nothing) end +local function fromString(s) return M.fromStringImpl(s, M.isFinite, just, nothing) end local function isJust(m, v) return type(m) == "table" and m.tag == "just" and m.value == v end local function isNothing(m) return type(m) == "table" and m.tag == "nothing" end