7 ms·
If Scheme's numbers were like Scheme
- ianbicking 12y agoI mostly read this as an exposition on how painful other types in Scheme are - like, if numbers were as painful to use as ever other thing, what an absurd world that would be!
- soegaard 12y agoSo did I. So why have append for lists, and string-append for strings? Well, Scheme implementors were early on (still are) interested in writing efficient compilers - that affects the naming choices.
- gus_massa 12y agoIn the "Racket2" wish list ( https://github.com/plt/racket/wiki/Racket2 https://github.com/plt/racket/wiki/Racket2 ) there is an idea to use more generics: > Generic programming by default: map, fold, and friends are generic [in Racket2] and not specialized to lists. I have something similar in my private "language" that I use for internal projects, it also use that for append and length (actually len, because length is too verbose). And I use only list-append or string-append in the few cases where the speed is critical. If something like this is implemented, the transformation from append to list-append or string-append could be made automatically in some cases by the Typed Racket optimizer (or the core optimizer).
- davexunit 12y ago>So why have append for lists, and string-append for strings? Because concatenating two lists and concatenating 2 strings are distinctly different operations on different data types, and it helps that they are named as such.
- copsarebastards 12y ago> Because concatenating two lists and concatenating 2 strings are distinctly different operations on different data types, and it helps that they are named as such. "Named" is the wrong word for that sentence. Names are for people, boats, pets, not data structures. You probably meant "data type named".
- codyb 12y agoThe alternative might make sense as well, that continuous mathematics is incredibly difficult to implement digitally. Fractions, tons of operators, rounding, irrationals, transcendentals, important constants, etc. The comparisons are interesting because of the limits of computer accuracy. In the end its probably a bit of both.
- nyir 12y agoBut also as an example of how fragmented the language becomes due to the splitting off of SRFI libraries instead of having a big but convenient ball of mud (CL).
- davexunit 12y ago>if numbers were as painful to use as ever other thing Other data structures aren't painful to use in Scheme.
- jrochkind1 12y agoI'm pretty sure that is part of how it was intended?
- cousin_it 12y agoFair points. We can see similar examples in other languages, e.g. C++ strings are "like C++" and a pain to use, while Java strings are "not like Java" and a pleasure to use. Maybe language design really isn't about general-purpose elegance, but about finding good special-purpose solutions.
- Retra 12y agoI've always said that language development should follow library development. Think about what your standard libraries are going to do, then write the language for doing those tasks consistently and elegantly. I'm always disappointed when I see a language with syntax and semantics but no real library. You have no way of knowing if it is a good design. It's like buying building parts out of a catalogue and hoping the architect will be able to build you something great with what you've ordered.
- jarcane 12y agoOn the other hand, Haskell strings are "like Haskell" (ie. they're lists like almost everything else), and it's actually because of that they're such a joy to use. "Strings as lists of chars" in a language with first-class functions is an absolute pleasure.
- tome 12y agoThat's a rather starry-eyed view of Haskell's String type. It has terrible performance in terms of both memory and time, which is why we now have Text instead.
- cousin_it 12y agoI think the Haskell community has realized by now that they should've made strings an abstract data type, with the freedom to change implementations in the future, like it's done in Java. See the ByteString and Text libraries, and the OverloadedStrings language extension.
- dschiptsov 12y agoFacepalm. Numerical Tower is Scheme's invention. It is one of Scheme's distinct features and a major innovation of that time. R5RS, which is considered the classic Scheme (some would even say R4RS) has only Strings and Vectors as an ADTs with such convention of naming procedures. It amounts for just one page of the standard. And, of course, not these two types is the essence of Scheme. Also Scheme precedes CL, which incorporates Numerical Tower from Scheme.
- coldtea 12y agoOnly he doesn't talk about Numerical Tower related features, but about how the numbers types are used.
- dschiptsov 12y agoExactly. The whole point of the Numerical Tower is in avoiding of such types, and using generic procedures and implicit coercion instead.
- deleted 12y ago[deleted]
- Confusion 12y agoOnce again you point out how someone is obviously a fool who doesn't know what he is talking about. Once again you completely miss the fact that he is actually quite knowledgeable and you have failed to read the post while giving the author sufficient credit to actually get his point. You probably don't realize how incredibly arrogant and condescending you seem.
- lispm 12y ago> It is one of Scheme's distinct features and a major innovation of that time. Is it? > Also Scheme precedes CL, which incorporates Numerical Tower from Scheme. I'd say it's different. R2RS appeared 1985... R2RS from 1985: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.18.1891 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.18.1... It mentions Common Lisp as the inspiration for it numeric capabilities. And Common Lisp got parts of it from Maclisp and Macsyma. Before that: R1RS. does not describe a numeric tower. ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-452.pdf
- wedesoft 12y agoNice idea because it would make for a more minimalistic core. One could then use some OO library (e.g. Guile's GOOPS) to implement polymorphic versions of+, -, *, etc. Edit: ... as well as methods for reading and displaying numbers.
- jonathanyc 12y agoIt's hard to see what the author is complaining about. I understand that it may just be a bit of fun, but in this post I'm going to try to address the points made and note how they don't seem valid to me. "What would Scheme be like if numbers followed the same style as the rest of the language? It would be necessary to import a library before using any numbers." Every language has primitive types. I don't see any Schemers complaining about that fact. Sure, maybe you find it annoying that you have to (import srfi-69) to use hashmaps, and that the accessor functions have verbose signatures: (hashmap-ref ht key), etc. I think the author is forgetting that Scheme gives you the power to easily define a new syntax for yourself that does not affect the regularity of the rest of the language. "Numbers would have no printed representation." I'm reading this as a complaint about there not being a default printing representation for types like records. I don't see how this is a valid complaint. The point of using a record is presumably to distinguish your data type from any old vector. Almost all implementations will allow you to define your own printed representation if you want. "There would be no polymorphism. Most operations would include a type in their name." R5RS does not have type signatures for functions. If you want to write a ref procedure that works on vectors and lists, you can. In fact: (define (ref x n) (cond ((list? x) (list-ref x n)) ((vector? x) (vector-ref x n)) (else #f))) "But the lack of polymorphism would make it even more obvious that in practice exactness was simply one of the type distinctions: that between floats and everything else." For lack of a better word, this seems like a strawman. I think it was a practical idea to have the language distinguish between exact and inexact numbers. Interestingly, Chicken Scheme implements the numeric tower in an library (the numbers egg) instead of in the standard distribution. "Names would be descriptive, like inexact-rational-square-root and exact-integer-greatest-common-divisor." I much prefer descriptive names that I can easily shorten using macros or functions to overloading the binary shift operator to write to streams. "Converting the lists into strings would be up to you." I guess this is a complaint about how small the standard library is. This is part of a larger debate within the Scheme community. See R7RS-large vs. R7RS-small. Many people think the latter is more to the nature of Scheme. "This would really be about whether numeric operations should always return fresh numbers, and whether the compiler would be allowed to copy them, but no one would mention these merely implementational issues." Relying on undefined behavior is an implementational issue. To quote R5Rs, "Eq?'s behavior on numbers and characters is implementation-dependent, but it will always return either true or false, and will return true only when eqv? would also return true." If you want defined behavior, why are you comparing things that can't already be compared with =, string=?, & co? Comparing a vector to a number doesn't make much sense. "There would still be no bitwise operations on integers. Schemers who understood the purpose would advise using an implementation that supports bitvectors instead of abusing numbers. Those who did not would say they're easy to implement." This point I am sympathetic to. But it seems to me a bit like complaining new language X does not support feature Y that language Z does. If feature Y is so important, why not decide whether or not it's worth your time to implement it and if not go with whatever language would be the most convenient to you? It's the same as many other decisions in life.
- vog 12y ago> Most operations would include a type in their name. Interestingly, this is the case in OCaml (albeit with a shorter syntax), and it is very handy. OCaml has two separate operators for integer addition (+) and float addition (+.), and it is illegal to write something like "1.5 + 1.5", as you either have to write "1.5 +. 1.5" or convert them to integers. This is used for the strong type checking of OCaml. While this seems annoying at first, I found this to be very practical, especially in numerical algorithms. In other languages like C/C++/Java you always struggle with implicit conversions between int and double. When do these really happen, given all those implicit rules? If you care about correctness, you'll find yourself casting stuff to double or int/long, like this: (double)(SOME_EXPRESSION) / (double)(ANOTHER_EXPRESSION) just to be sure this is really a floating division happening there, rather than an integer division that throws away accuracy. In OCaml, you just write: (SOME_EXPRESSION) /. (ANOTHER_EXPRESSION) and have a guaranteed floating point division, as well as a typecheck telling you when you e.g. forgot to convert SOME_EXPRESSION from integer to floating point. You'll then have to add explicit conversions wherever needed, but this is really the lesser evil – especially since it gives you full control over when this actually happens.
- JadeNB 12y ago> This is needed for stronger type checking. Is 'needed' (as opposed to 'used') really correct here? Haskell's type classes manage to handle the type checking for different kinds of addition perfectly well without an explicitly different operator: > :t 1 + 1 1 + 1 :: Num a => a > :t 1.5 + 1.5 1.5 + 1.5 :: Fractional a => a In other words, since 1 makes sense as an element of any 'Num'mable type, so does 1 + 1; but, since 1.5 only makes sense as an element of a 'Fractional'able type, we can only regard 1.5 + 1.5 as an element of those more restrictive types.
- vog 12y agoIndeed, I meant "used". Fixed this in my comment above. Thanks!
- username223 12y ago> In other languages like C/C++/Java you always struggle with implicit conversions between int and double. Not that I've noticed. Uni-typed operators are essential in something like Perl, which has lots of implicit conversions (think of the horrible "+" operator in PHP, or "|" in Perl). They're also helpful in something with type inference like Ocaml, though Haskell does okay without them. But with the plentiful explicit type declarations in C-style languages, polymorphic operators are rarely confusing.
- srpablo 12y agoReminds me of the 2009 Scheme Steering Committee Position Statement, they stated (correctly, imo) "the Scheme community has rarely missed an opportunity to miss an opportunity."[1] I think many of the design choices the author is griping about (which numbers mercifully avoid) is an illustration of this tendency, which itself is a result of the two boats Scheme had a leg in for years: both a minimalistic language with elegant semantics, useful for pedagogy and optimal for hobby implementations ("50-page purists") and a viable, modern, competitive language for nontrivial applications. Despite all this, you'll take my Scheme and Racket away from my cold, dead hands. [1]: http://www.scheme-reports.org/2009/position-statement.html http://www.scheme-reports.org/2009/position-statement.html
- yvdriess 12y agoThe thing is that there is already a Lisp that is a viable, modern and competitive language for nontrivial applications. One that has incorporated the institutional knowledge and hindsight of two decades pragmatic programming practices. I love Scheme as a first-boat language, but dread every new R(+1 N)RS for the inevitable shift towards the rest-boat language design.