Sorting anything with Execute JavaScript actions

Later version – the two functions are interchangeable in the ES6 original, but the current version uses the fold (rather than iterative version)

(In the very first upload, I had inadvertently posted a version in which I was testing the alternative iterative draft – looks like you got that copy before I corrected it. I can see that that must have been confusing - my apologies :slight_smile: )

Better to use the fold (either by editing your copy or downloading the current one) – as you have found in ES5 conversion, there’s always a bit more that can go wrong in an iterative mutation than in a fold. The reduce/fold mechanism handles the messier details for us.

( and has a surprisingly wide range of application - a ‘fold’ or ‘reduce’ function is really the most powerful and reliable ‘swiss army knife’ in any language. Part of the beauty of it is that we don’t need to know how it is implemented – in some languages it would make most sense to do it recursively, in others iteratively – all we need to know is that it is taking care of the details and mechanics for us. )

One way of understanding it might be to look at an equivalent (called foldl, as in ‘fold left’ – there is also a ‘foldr’, which in JS is provided in the form of Array.reduceRight)

AppleScript version of foldl / reduce

on run
    script sum
        on |λ|(accumulator, x)
            accumulator + x
        end |λ|
    end script
    
    foldl(sum, 0, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
    
    --> 55
end run


-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- For comparison: foldr, essentially equivalent to the JS Array.reduceRight
-- though it traditionally expects a function on (x, accumulator)
-- whereas a foldl expects a function on (accumulator, x)
-- (JS uses the (acc, x) pattern for both reduce and reduceRight)

-- foldr :: (b -> a -> a) -> a -> [b] -> a
on foldr(f, startValue, xs)
	tell mReturn(f)
		set v to startValue
		set lng to length of xs
		repeat with i from lng to 1 by -1
			set v to |λ|(item i of xs, v, i, xs)
		end repeat
		return v
	end tell
end foldr

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: Handler -> Script
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

Fold version of mappendComparing:

    // mappendFoldComparing :: [((a -> b), Bool)] -> (a -> a -> Ordering)
    const mappendFoldComparing = fbs =>
        (x, y) => fbs.reduce(
            (ord, [f, bool]) => ord !== 0 ? ord : (
                (bool ? id : flip)(compare)(f(x), f(y))
            ), 0
        );