Re: [racket-dev] [plt] Push #26002: master branch updated
On 01/01/2013 12:36 PM, mfl...@racket-lang.org wrote: 07d5a9e Matthew Flatt 2013-01-01 12:31 : | fix `expt' on small negative number and large positive odd | | The pow() function apparently gets it wrong on some platforms. | | Closes PR 13391 Thanks, Matthew. I'm looking forward to getting bugged by DrDr less. :D One question about the fix: src/racket/src/number.c ~~~ --- OLD/src/racket/src/number.c +++ NEW/src/racket/src/number.c @@ -2729,7 +2729,16 @@ static double sch_pow(double x, double y) return scheme_infinity_val; } } else { -return protected_pow(x, y); +double r; +r = protected_pow(x, y); +if ((r == 0.0) && !minus_zero_p(r)) { + /* check large odd power of a small negative number, + which some libraries get wrong for some reason */ + if ((x < 0) && (fmod(y, 2.0) == 1.0)) { + r = scheme_floating_point_nzero; + } +} +return r; } } #endif I looked into fixing this myself, and identified this as a spot to change. I also saw some JIT-looking stuff for `flexpt' that looked kind of like it was machine code, so I didn't try to fix it. Does this code you just changed get compiled during the build and then inlined by the JIT? Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] [plt] Push #26002: master branch updated
At Tue, 01 Jan 2013 14:16:27 -0700, Neil Toronto wrote: > I looked into fixing this myself, and identified this as a spot to > change. I also saw some JIT-looking stuff for `flexpt' that looked kind > of like it was machine code, so I didn't try to fix it. Does this code > you just changed get compiled during the build and then inlined by the JIT? In the case of `flexpt', the "inlined" code is just a call to the sch_pow() C function (which is "inline" enough to avoid boxing). _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] Five feature/limitation interactions conspire to drive mad
On Dec 31, 2012, at 6:32 PM, Sam Tobin-Hochstadt wrote: > I'm not sure that an ad-hoc naming solution is the right thing. I > really want to avoid adding more ad-hoc complexity to the Typed Racket > type checker, and instead work on simplifying it into something that > can be more precisely characterized, and thus be more sure that it's > implemented correctly. > > Is there a generalization of this solution that we can give a clean story for? "Sometimes you have to make the internals quite complex to make it all appear elegant and simple." Guy Steele, as conveyed by Matthew and confirmed by Sam _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] Five feature/limitation interactions conspire to drive mad
Neil, thanks for the user story. We should hear more of those for all kinds of corners in our world. Question: did you start the math library in an untyped form (and switch) or did you go with types from the get-go? -- Matthias On Dec 31, 2012, at 3:27 PM, Neil Toronto wrote: > The subject sounds complainy, and so will the rest of this email. So I will > state up front that I love Typed Racket, and I'm only frustrated because I > want to love it more. > > Also, I apologize for the length of this email, but I have to tell a story. > Otherwise, I'll get a bunch of "Why don't you try this?" replies, which I'll > have to answer, leading to an inseparable tangle of ideas. How the features > and limitations interact is not always obvious. > > The features and limitations are: > > 1. The reader is set by the #lang line, but not submodule forms. > > 2. Implicit argument types in let loops are generalized from the types >of their initial values. > > 3. let: loops require every argument type and the return type to be >annotated. > > 4. TR can't produce contracts for single-arity `case->' types. > > 5. Using single-arity `case->' types makes annotating function bodies >in certain ways impossible. > > So here's my user story. > > ** ONCE UPON A TIME ** > > I'm working on `math/matrix'. TR doesn't do generics, which is fine for now, > but it means a lot of the matrix library's functions have to have > single-arity types like this: > > (: matrix-hermitian (case-> ((Matrix Real) -> (Matrix Real)) > ((Matrix Number) -> (Matrix Number > > It could be (Matrix Number) -> (Matrix Number). But the real matrices are > closed under almost every matrix operation, so `math/matrix' shouldn't make > users worry needlessly about complex numbers. > > Annotating expressions inside the bodies of functions with single-arity > `case->' types like that is often impossible, because there's no name for > polymorphic type arguments (in this case, either `Real' or `Number'). To > separate the issues from `math/matrix', consider this function instead: > > (: repeat+1 (case-> (Index Real -> (Listof Real)) > (Index Number -> (Listof Number > (define (repeat+1 n num) >(let loop ([i 0] [acc empty]) > (cond [(< i n) (loop (+ i 1) (cons (+ num 1) acc))] >[else acc]))) > > It should act like this: > > > (repeat+1 3 10) > - : (Listof Real) > '(11 11 11) > > (repeat+1 0 11+4i) > - : (Listof Number) > '() > > But it doesn't type: > > Type Checker: Expected (Listof Real), but got (Listof Any) in: acc > Type Checker: Expected (Listof Number), but got (Listof Any) in: acc > > The highlighted expression is the `acc' inside of [else acc]. The causes: TR > gives the expression `empty' the type (Listof Any) in both passes through the > function body (one for each case). > > The level of inference TR does is generally fine, requiring few annotations. > The problem here is that *I can't annotate `empty'*. I don't have a name for > the type argument to `Listof'. > > Here's one annotation-less solution: > > (define (repeat+1 n num) >(cond [(= n 0) empty] > [else > (let loop ([i 1] [acc (list (+ num 1))]) > (cond [(< i n) (loop (+ i 1) (cons (+ num 1) acc))] > [else acc]))])) > > TR helpfully generalizes the type of (list (+ num 1)) from (List Real) to > (Listof Real) in the first typechecking pass and from (List Number) to > (Listof Number) in the second typechecking pass, so `acc' has the correct > type in both passes. > > I committed the off-by-one error [i 0] and the copy error [acc (list num)] > while deriving that solution. Not liking either kind of error, I figure this > is safer, and also cleverer: > > (define (repeat+1 n num) >(let loop ([i 0] [acc (rest (list num))]) > (cond [(< i n) (loop (+ i 1) (cons (+ num 1) acc))] >[else acc]))) > > I'm trying to get a properly typed `empty' by taking the rest of a > one-element list. > > I get two type errors like this, highlighting (cons (+ num 1) acc): > > Type Checker: Polymorphic function cons could not be applied to > arguments: > Types: a (Listof a) -> (Listof a) > a b -> (Pairof a b) > Arguments: Real (Listof Nothing) > Expected result: (Listof Nothing) > > Ah, I see what happened. TR generalized from the type of (rest (list num)), > which is (Listof Nothing) because (list num) has the type (List Real) or > (List Number). I need to force it to generalize differently. One way to do > that is to turn the base case into a call to a polymorphic function like > `empty-listof': > > (define (repeat+1 n num) >(let loop ([i 0] [acc (empty-listof num)]) > (cond [(< i n) (loop (+ i 1) (cons (+ num 1) acc))] >[else acc]))) > > (: empty-listof (All (A) (A -> (Listof A > (define (empty-listof x) (rest (list x))
[racket-dev] Working on Ragg. Suggestions?
Hi everyone, I've been working on a parsing framework with the design goal to be easy to use. I'm calling it "ragg": Racket AST Generator Generator. (It used to be called 'autogrammar', but that was too much of a mouthful. Thanks to Joe Politz for the new name!) The current source code uses PLaneT2 conventions: https://github.com/dyoo/ragg The beginnings of its documentation can be read here: http://hashcollision.org/ragg/ Major features: * Ragg provides a #lang for writing extended BNF grammars. Modules written in #lang ragg automatically generate a parser. It tries to follow HTDP doctrine, for the structure of the grammar informs the structure of the parser's output: the generated parsers produces native Racket syntax objects in the same shape as the rules. The documentation link above shows a trivial example, and I'll put more substantive examples and uses in: https://github.com/dyoo/ragg/blob/master/ragg/examples https://github.com/dyoo/ragg/blob/master/ragg/test (Note: the Python parser example works! It's basically a copy and paste of the one in the original Python source tree.) * The language uses an uppercase convention to determine if a production is a terminal token or not. Tokens can optionally provide location, and the generated syntax objects will have source location if the tokens do. * Ragg should work on ambiguous grammars. I'm using a parser based (hilariously enough) on the cfg-parser from the algol60 collection, rather than the more finicky LALR parser in parser-tools/yacc. --- I need to polish ragg. I'm going to get most of the test cases, error traps, and documentation done by the end of this week. I would really like some comments and suggestions before I release this on PLaneT2, because I do want this to be useful to other people. In my view, the big thing missing is a story about lexers, which I don't quite know what to do yet, and if anyone has ideas, I'd love to hear them. Other work: I don't know if cfg-parser has been optimized yet. I'll have to investigate that. Hope this helps! _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] [plt] Push #26005: master branch updated
On 01/01/2013 04:16 PM, stamo...@racket-lang.org wrote: stamourv has updated `master' from 1f8370d2d6 to 678451f8c4. http://git.racket-lang.org/plt/1f8370d2d6..678451f8c4 =[ 2 Commits ]== Directory summary: 10.3% collects/tests/typed-racket/succeed/ 8.6% collects/tests/typed-racket/unit-tests/ 81.0% collects/typed-racket/base-env/ ~~ 4137eb9 Vincent St-Amour 2012-12-31 17:26 : | Make let: annotations optional. : I think I can remove every instance of #{v : t} from my code now. Yay! Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] Five feature/limitation interactions conspire to drive mad
On 01/01/2013 03:35 PM, Matthias Felleisen wrote: Neil, thanks for the user story. We should hear more of those for all kinds of corners in our world. You're welcome! Question: did you start the math library in an untyped form (and switch) or did you go with types from the get-go? It's all been in Typed Racket from the beginning. This was initially because I mostly had floating-point functions planned, and I wanted TR's help proving that I never used non-flonums by mistake. Also, I wanted the special functions to have performance competitive with C implementations. When I decided to do arrays, Typed Racket was again the natural choice. First, because it's not possible to use `require/typed' to import polymorphic struct types. Second, because it allowed me to avoid a lot of runtime checks. I discovered reasons #3 and #4 while I was writing `math/array': 3. Passing around higher-order functions can get confusing. I can't speak for anyone else, but when I get something like `array-axis-reduce' - which is like a fold but with complicated types - to pass the type checker, my code is usually correct. 4. TR's types for Racket's numeric tower, especially the additional `Index' type, makes it easy to safely use unsafe indexing. Throughout `math/array', values of type `Index' are always either a size (e.g. a vector length) or an index that has been proved to be less than a size. IOW, if I can get TR to prove j : Index, I'm satisfied that (unsafe-vector-ref xs j) is actually safe. Also, if `j' is a loop counter, TR can usually compare and increment using unsafe fixnum ops. There are a bunch of other little things that are like #4 (which is only a big thing because indexes are so prevalent in `math/array'). Maybe I'll collect those into a separate user story. Neil ⊥ _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] TR: Five feature/limitation interactions conspire to drive mad
On 12/31/2012 02:56 PM, Vincent St-Amour wrote: At Mon, 31 Dec 2012 13:27:50 -0700, Neil Toronto wrote: 2. Don't generalize argument types in let loops. This is a bad idea. Often, inferring the types of loops only works because of type generalization. Agreed. Since this one is only a problem because of the other limitations you list, ideally we should fix the others and leave this one alone. Do you agree? Very yes. 3. Allow let: loops to have unannotated arguments and return values. This would totally work. I could use [i : Nonnegative-Fixnum 0] instead of [#{i : Nonnegative-Fixnum} 0], and still not have to annotate `acc' or the loop's return value. Trying this one right now. Thanks again. :D 4. Extend the set of types TR can produce contracts for. This probably only works for first-order function types. It would be helpful, but may not even work for functions with `Array' or `Matrix' arguments (they're higher-order). I can look into making contract generation smarter. Could you send me a list of types that caused you issues with contract generation? Actual examples are attached as a standalone Typed Racket program, with the function bodies stubbed out. I think they cover pretty much all the uses of `require/untyped-contract' in the math library. Neil ⊥ #lang typed/racket (struct: (A) Array ()) (define-type Indexes (Vectorof Index)) (define-type In-Indexes (U Indexes (Vectorof Integer))) ;; --- ;; Changing argument types from In-Indexes to (Vectorof Integer) ;; Most uses of `require/untyped-contract' in `math/array' are for this. (: make-array (All (A) (In-Indexes A -> (Array A (define (make-array ds v) (error 'undefined)) ;; The contract can be created, but is ambiguous and always fails. Exported to untyped Racket using ;; this subtype: #;(All (A) ((Vectorof Integer) A -> (Array A))) ;; --- ;; array-map's type ;; There was no subtype of this under which I could export it to untyped code: (: array-map (All (R A B T ...) (case-> ((-> R) -> (Array R)) ((A -> R) (Array A) -> (Array R)) ((A B T ... T -> R) (Array A) (Array B) (Array T) ... T -> (Array R) (define array-map (case-lambda [(f) (error 'undefined)] [(f arr) (error 'undefined)] [(f arr0 arr1) (error 'undefined)] [(f arr0 arr1 . arrs) (error 'undefined)])) ;; I ended up making a separate, typed implementation for untyped code, with the type #;(All (R A) (case-> ((-> R) -> (Array R)) ((A -> R) (Array A) -> (Array R)) ((A A A * -> R) (Array A) (Array A) (Array A) * -> (Array R ;; --- ;; Matrix argument types ;; Almost all uses of `require/untyped-contract' in `math/matrix' are for this. (: matrix-determinant (case-> ((Array Real) -> Real) ((Array Number) -> Number))) (define (matrix-determinant M) (error 'undefined)) ;; Exported using the subtype #;((Array Number) -> Number) ;; --- ;; First-order numeric functions ;; Almost all uses of `require/untyped-contract' in `math/number-theory' and `math/special-functions' ;; are variations of the following: (: factorial (case-> (Zero -> One) (One -> One) (Integer -> Positive-Integer))) (define (factorial n) (error 'undefined)) ;; Exported using the subtype #;(Integer -> Positive-Integer) _ Racket Developers list: http://lists.racket-lang.org/dev
Re: [racket-dev] Five feature/limitation interactions conspire to drive mad
All good points on TR development flows. If I could elaborate from my perspective on Neils' #3. I think this is the #1 benefit of TR over R. Yes, static type checking, real-time while you type is superb road kill on the highway of code development And I do enjoy it so. BUT what TR really, really grants is the ability to just get META with HOF and not go insane, all evidence to the contrary, while doing so. For me, cursed with wrong end of the bell curve working set intelligence, the following example of HOF without TR's training wheels would result in a multi-week rest visit to Arkham for me if undertaken in plain ol' R. e.g quick sample from some proto code. https://github.com/RayRacine/racketlib/blob/master/io/iteratee/iteratee.rkt https://github.com/RayRacine/racketlib/blob/master/mapred/types.rkt https://github.com/RayRacine/racketlib/blob/master/mapred/shuffle/merge-sort.rkt BTW, I'm throwing down an inferencing gauntlet. Here is a convenient example of where TR's inferencing falls a bit short. In merge-sort.rkt above. (: merge-sort-inmem-blocks-to-disc (All (D) (Listof (Listof D)) (Sorter D) (Writer D) -> (Listof (Block D (define (merge-sort-inmem-blocks-to-disc lst-data sorter writer) (let: ((enum : (Enumerator D (Listof (Block D))) (enumerator/select-from-n-lists lst-data sorter)) (iter : (Iteratee D (Listof (Block D))) (iter-block (generate-rdd-block-filename) writer))) (icomplete (enum iter Here the let: bindings are necessary hints for TR inferencing to succeed. I'd prefer. (: merge-sort-inmem-blocks-to-disc (All (D) (Listof (Listof D)) (Sorter D) ( Writer D) -> (Listof (Block D (define (merge-sort-inmem-blocks-to-disc lst-data sorter writer) (icomplete ((enumerator/select-from-n-lists lst-data sorter) (iter-bloc (generate-rdd-block-filename) writer))) Random musing follows. If I could lay on more subject anecdote. Consider Scala, probably envisioned by Martin O. as a "properly" done core OO language with relatively seamless functional layering, i.e., lambda smoothly filled in around the edges. An unintended consequence, I think, was how hell bent a serious subset of Scala users were to "use" Scala as a Functional Language at the core with OO smoothly filled in around the edges. Scalaz, Scala Type Classes et al. A substantial core of Scala user effort in and around essentially coding Haskell in Scala. Abusing the analogy towards TR and R. I think a potential unintended consequence is that TR will encourage continued user pressure on TR development for further ability to code "Haskell" in TR e.g. Co/contra type variance (for collections), type bounds, generics (data types), , TRing of generics methods (gen:*) setting a basis for TR's version of Type Classes, etc. Extrapolating to a hypothetical future, TR will ultimately result in a distinct separation in from R. Technically, the development of a library in TR will always allow for some sort of mechanical means of isomorphic translation to R. Practically, future libraries in TR will get more and more HOF (Haskell-idiomatic if you will) like and mapping down to R, which will technically work/run, however code/library interfaces will retain their HOF characteristics to such an extant that use in R coding will be a struggle. Though leverage lifting R into TR, analogous how Scala supports leveraging the vast amount of Java code will be common. In other words, three years from now, the same developer fluent in R and TR idioms, developing the same library, would fundamentally write two different libraries, technically isomorphic (translatable), but practically for-use distinct. Bottom line wild hair prediction. Beyond Racket core collections which by skill and effort by core maintainers to be bi-use (R and TR), future 3rd party libraries / collections will be TR xor R in nature. While I grant it is a huge overreach to offer analogy of religious wars into programming language musings, TR and R may very well turn out to be Catholic and Protestants (Emacs and Vi) all over again. You are one or the other and rarely both. On Tue, Jan 1, 2013 at 7:42 PM, Neil Toronto wrote: > On 01/01/2013 03:35 PM, Matthias Felleisen wrote: > >> >> Neil, >> >> thanks for the user story. We should hear more of those for all kinds of >> corners in our world. >> > > You're welcome! > > Question: did you start the math library in an untyped form (and switch) >> or did you go with types from the get-go? >> > > It's all been in Typed Racket from the beginning. This was initially > because I mostly had floating-point functions planned, and I wanted TR's > help proving that I never used non-flonums by mistake. Also, I wanted the > special functions to have performance competitive with C implementations. > > When I decided to do arrays, Typed Racket was again the natural choice. > First, because it's not possible to use `require/typed' to import > polymorphic struct types. Second, because it allowed me to avoid