Found out last night that
Array.reduce
in Godot 4.4 does not work
the way I would have expected coming from a
functional programming background.
I wanted to write a function which would fold
over a list and return best suitable match based on
some criteria or null
if none of those
results were appropriate. However, I found that when
I used reduce
, it would keep picking an
inappropriate result (which happened to be at the
front of the list).
According to the documentation for reduce
,
this is because of how the accum
parameter works:
The method takes two arguments: the current value of
accum
and the current array element. Ifaccum
isnull
(as by default), the iteration will start from the second element, with the first one used as initial value ofaccum
.
Which means that even though reduce
has the same type signature as foldl
,
if accum
happens to be null it turns
into what would be a foldl1
in Haskell.
The solution was to use a for
loop
instead.
A chatter Reaganomicon
mentioned
that JavaScript, F#, and Python's
functools
also implement reduce in the
same way.
JavaScript does implement reduce
in a similar way:
The value resulting from the previous call to
callbackFn
. On the first call, its value isinitialValue
if the latter is specified; otherwise its value isarray[0]
.
But, if you call reduce
with
null
or undefined
, the
function works correctly (at least in Firefox
136.0):
console.log([1].reduce((acc, v) => null, null)) console.log([1].reduce((acc, v) => null, undefined)) console.log([1].reduce((acc, v) => null))
Prints:
null null 1
This is probably because JavaScript functions can check how many arguments a user defined even if one of those arguments is undefined.
F# also does
it correctly as it has both
Array.fold folder state array
and
Array.reduce reduction array
(which
have the same type signatures as foldl
and foldl1
respectively in Haskell)
And it turns out that functools
in
Python 3 also implements reduce
correctly:
import functools print(functools.reduce(lambda x, y: None, [1], None)) print(functools.reduce(lambda x, y: None, [], 1))
Prints:
None 1