>Doing Advent of Code 2024, I was trying to use `sorted?` procedure. And 
something bothered me.
>
>The reference says :
>
>    Scheme Procedure: *sorted?* items less
>    C Function: *scm_sorted_p* (items, less)
>
>        Return |#t| if items is a list or vector such that, for each
>        element x and the next element y of items, |(less y x)| returns
>        |#f|. Otherwise return |#f|.
>
>I think the description should be :
>
>    Return |#t| if items is a list or vector such that, for each element
>    x and the next element y of items, |(less y x)| returns |#t|.
>    Otherwise return |#f|.
>

It shouldn’t. Let’s start with your example:

>Then, testing it in the REPL give me this :
>
>scheme@(guile-user)> (sorted? '(1 2 3) <)
>$13 = #t
>
>So far so good.
>
>scheme@(guile-user)> (sorted? '(3 2 1) <)
>$16 = #f

Consider the simpler case (sorted? '(1 2) <). This should, and does, return 
#true.

In this example, x=1 and y=2. Then, (less y x) is (< 2 1). This evaluates to 
#false. Since #false isn’t #true, according to the first description, (sorted? 
'(1 2) <) return #true. So, first description is ok in this case! Likewise, it 
is ok for (sorted? '(2 1) <).

However, the second description is wrong (just go over it step-by-step again if 
needed).

There is also another, more subtle thing going on. Conventionally, all values 
are truth values: everything not #false is considered to be ‘true’ (in Guile 
Scheme, also #nil is counted like #false I think, not sure). In Scheme, while a 
predicate (*) that is exposed (e.g. exported from a module) should produce only 
#t or #f as truth values (with some exceptions, like when it would prevent 
tail-calls, or when it invokes another caller-provided predicate that produces 
other truth values, it doesn’t need to normalise that), it’s usually fine for a 
predicate supplied by the caller (‘less’, in this case) to produce other truth 
values.

Because of that reason, it needs to be phrased in terms of #false instead of 
#true (actually #false->false, to account for #nil).

(*) in a general sense, also including multiple-variable relations.

>scheme@(guile-user)> (sorted? '(1 1) <)
$17 = #t

>I was expecting #f due to

>scheme@(guile-user)> (< 1 1)
>$18 = #f

By the second description, sure.
But by the first description, it is fine!

My guess is that it’s intentional, so that you can save one keystroke to write 
(sorted? '(1 1) <) instead of (sorted? '(1 2) <=).

Although, the description could use a bit of expansion to make clear what 
happens in the case that two elements are equal, and put emphasis on it really 
being ‘less’, not ‘less-than-or-equal-to’.

Best regards,
Maxime Devos
  • RE: sorted? Maxime Devos via General Guile related discussions

Reply via email to