Hi Richard,

Now that's much clearer to me:
        min{y | y in c . y > x} "strict supremum"
        max{y | y in c . y < x} "strict infimum"


For the general case of a sequence (not sorted) of elements we can do


        strictSupremumOf: x in: sequence


                ^(sequence transduce filter: [:y | y > x])              
"virtual sequence"
                        inject: nil
                        into: [:min :b | min ifNotNil: [:a | a min: b]]


I just picked a variant of minimum that answers nil if no element is found. 
Other variants would work, too.
The focus of transducers is on re-use and composition of processing steps. We 
can break this up into steps if needed:


        minimum := [:min :b | min ifNotNil: [:a | a min: b]] init: nil. 
"reduction"
        upperBounds := Filter predicate: [:y | y > x].                          
"transducer"
        strictSup := minimum transduce: upperBounds.                    
"transformed reduction"
        ^strictSup reduce: sequence


We can also use a different notation similar to a data flow:


        minimum <~ upperBounds <~ sequence


Of course, if we know how the sequence is sorted, we should use another 
algorithm. Assuming an ascending order with no random access, we'd change 
minimum to stop early:


        minimum := [:min :b | Stop result: b].


Kind regards,
Steffen



Richard O'Keefe schrieb am Freitag, 21. April 2023 05:33:44 (+02:00):


successor of x in c = the smallest element of c that is larger than x
 min {y | y in c . y > x}

predecessor of x in c = the largest element of c that is smaller than x
 max {y | y in c . y < x}



On Thu, 20 Apr 2023 at 21:08, Steffen Märcker <merk...@web.de> wrote:

Dear Richard,


thanks for that additional piece. I'll put insert-<left/right> on my list of 
possible variants. I think we come back to naming after the initial port is 
done and everyone can play with it. Generally, I made the observation to better 
be careful with names since it's too easy to alienate other or trigger wrong 
assumptions.


New  topic! (quote below)


Honestly, my knowledge of Haskell is rather limited and rusted. Hence, I am 
having difficulties understanding what exactly these operations with a sequence 
of elements. Can you give an example or some pseude/smalltalk code from your 
use-case and library?


Kind regards


Changing the subject a wee bit, there's an operation family
in my library, and I wonder how it would fit into Transducers?
To avoid bias, here's a specification in Haskell (for lists,
because I haven't had any luck installing Data.Witherable).


uccessorBy, predecessorBy :: (a -> a -> Ordering) -> a -> [a] -> a
successor,   predecessor   :: Ord a                => a -> [a] -> a

successor = successorBy compare

successorBy cmp x = minimumBy cmp . filter (\y -> cmp x y == LT)

predecessor = predecessorBy compare

predecessorBy cmp = successorBy (flip cmp)


The reason these operations exist is to pick neighbouring
elements in SortedCollections and SortedSets.  But they make
*sense* for any Enumerable.  So there are "generic"
definitions with orderrides for those two classes.


A filter + a reduce .  Traditionally, a #select:thenFold:ifNone:
in order to avoid building an intermediate collection.  That much
I see how to do with transducers.  But you can't get the desired
override for #successor:[sortBlock:][ifNone:] by overriding
#select:thenFold:ifNone: in SortedCollection or SortedSet.  So what
*should* one do?

-- 
Gesendet mit Vivaldi Mail. Laden Sie Vivaldi kostenlos unter vivaldi.com 
herunter

Reply via email to