make it so that (=? "hi" "hi") works
Sandra Snan
(25 May 2021 15:38 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(25 May 2021 15:55 UTC)
|
Re: make it so that (=? "hi" "hi") works
Shiro Kawai
(26 May 2021 00:57 UTC)
|
Re: make it so that (=? "hi" "hi") works
John Cowan
(26 May 2021 03:58 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 06:08 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 06:31 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 06:35 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 06:12 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 06:31 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 06:41 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 06:49 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 06:59 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 07:10 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 06:50 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 07:09 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 07:35 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 07:48 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 07:56 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 08:13 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 08:34 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 08:55 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 09:15 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 10:27 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 10:53 UTC)
|
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 12:15 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 13:55 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 14:32 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 15:20 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 17:02 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 17:37 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 17:48 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 18:12 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 18:20 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 18:40 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 19:06 UTC)
|
Re: make it so that (=? "hi" "hi") works
Marc Nieper-Wißkirchen
(26 May 2021 19:25 UTC)
|
Re: make it so that (=? "hi" "hi") works
Sandra Snan
(26 May 2021 19:38 UTC)
|
Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> writes: > I may be more persuadable if you can show how to prevent that code using > your interface doesn't become highly inefficient. Sure. We already have equal? to compare deep structures. It can inherently also compare atomic structures (inefficiently, compared to eq?, string=?, and =, for example). In order to write efficient Scheme code it's important to know when to use equal? and when to use type-specific comparison. Similarly, it's important to know when to use a generic =? and when to use string=? Here is an implementation of generics that expands to idiomatic cond pred? clauses. https://idiomdrottning.org/call-table-generics Notably, the most recently registered generics are tried first, and it expands to: (cond ((and (string? a) (string? b)) (string=? a b)) (...)) This is on par with equals? (define-generic (frob (string? a) (string? b)) (string=? a b)) (time (dotimes (i 10000000) (frob "The quick brown fox jumps over the lazy dog" "The quick brown fox jumps over the lazy dog"))) ⇒ 2.782s CPU time, 0.039s GC time (major), 936214/156033 mutations (total/tracked), 76/67033 GCs (major/minor), maximum live heap: 533.14 KiB (time (dotimes (i 10000000) (equal? "The quick brown fox jumps over the lazy dog" "The quick brown fox jumps over the lazy dog"))) ⇒ 1.738s CPU time, 0.023s GC time (major), 540142/90021 mutations (total/tracked), 42/40159 GCs (major/minor), maximum live heap: 533.09 KiB In a really tight loop, you'd want to use the type specific comparator. But, since the use case is for when you need, want, or feel like using generics, I don't have to compare to string=? or even to equals? My case here is that a generic =? with a stowed-away, extensible type record is faster than the "uncurried" version of =? in the SRFI interface. (time (dotimes (i 10000000) (foo (query-for-the-type-record) "The quick brown fox jumps over the lazy dog" "The quick brown fox jumps over the lazy dog"))) couldn't possibly be faster than mine, where the type record has already been unrolled (into cond clauses) during the binding of frob. So, let's keep the three different scenarios separate: • A. truly generic generics over an extensible type record object • B. generics over a supplied subset that only need to dispatch between a handful of types, such as monster sprites vs player sprites • C. type-specific monomorphic comparators such as string=? You can not use the speed of scenario C to argue against scenario A. Let's be clear about that. That leaves us with this: One, (=? (query-for-type-record) x y) is inherently more expensive than an (=? x y) with the type record hardcoded as long as those type records are the same. I.e. we are wholly within scenario A. That expense can only be justified if the speed-gains of scenario B — a shorter, better-ordered, domain-specific type-record (e.g. fewer cond clauses) — outweigh the call overhead cost of having to pass it as an argument each and every time. (Unless facilities such as define-syntactic-monad are used.) That has not been shown to be true for every compiler. My implementation has the default, plain-vanilla, in-almost-every-scheme types checked last and domain-specific, recently-extended types checked first. Making speed gains from B's tighter type record very small (yes, it's non-zero, but again the B approach introduces overhead of its own.). Two, It's possible that a compiler be more type-aware than RnRS facilities allow and that a compiler can create implementation-specific generic dispatching that are even faster than what we on the "user" / "library" side can implement. Call-table-generics expand to cond+and+pred clauses. A compiler with some amount of type-awareness could use another, internal, dispatching structure to be even more efficient. Within limits, of course, since Scheme has dynamic types. Three, To be clear about what the argument is here: It's which out of scenario A vs scenario B should have the shorter sweeter names and which out of scenario A vs scenario B should be saddled with the long and cumbersome names. That's it. Neither of us want to do away with string=? and string<? Either of us would be capable of import renaming or argument-fixing. Re-currying what the SRFI-128 spec has uncurried. (Speaking of inefficiency! SRFI-128's code turns ((foo* r) x y) into (foo r x y) and then we users of the library are expected turn it back into (bar x y)?) So the argument is which duo makes the most sense: • (=? default x y) • (=?/default x y) vs • (=? x y) • (=?/with-comparator comparator x y) That's what we are disagreeing about. Scenario B users not only wants to add their own types into the mix. They want to remove the default types. They want to write code that is "generic" not on all comparable types but instead only on their newly added types. Scenario A users don't always want to add new types in there, and when they do, they also want to their generic code to work on the default vanilla stuff. > The only point I am arguing about is that =? with an implicit default > comparator is not very helpful but would promote inefficient and too > generic code. Too generic. I want to write generic code. I don't think I would ever use the =? as they stand in the SRFI. If I want to compare between only specific types, I'm not sure I need the SRFI to do that. Helper procedures that turn an < into =, >, ≥, ≤ are simple to make (albeit expensively, compared to direct implementations of those if available). Let's say I have two custom types, bar and quux. I can make a bar-or-quux< and I can then use (map (make= bar-or-quux<) xs ys) This use case wouldn't even need the SRFI. The time for generic default implicit stuff is exploratory programming. (map =? xs ys) is great in a function you don't know for sure you'll keep or that it'll be a bottleneck. If it ends up being a well-loved function that you refer to often, well, that's when you can sharpen it up. And implement a proper, type-specific, bar-or-quux= function. > This is similar to sort (whether it takes a plain comparison predicate or a > comparator), which is generic as well. > > (=? c x y) is a good interface, which is to be used exactly in such generic > algorithms. It's not good because of the argument heterogenity and incompability with sort. ((=? c) x y) would solve that since you could then do (sort xs (=? c)) > It's true that coding (=? string-comparator string1 string2) doesn't make > much sense and that one should rather write (string=? string1 > string2). Yes, exactly. When I wrote before that you can't use the benefits of scenario C to argue against scenario A… What we can do is to use the benefits of scenario C to argue against scenario B! Since in scenario A you are writing generic code for all kinds of comparable types, while in scenario B as in scenario C you are writing code for known types. The pointlessness of (=? string-comparator string1 string2) is one of the best arguments for my case.