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
accumand the current array element. Ifaccumisnull(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 isinitialValueif 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