Re: [racket-users] Combining contract checking with normalization?

2022-03-16 Thread jackh...@gmail.com
This is also something I want and have thought about for some time. My main 
use case is for functions that I want to accept an arbitrary sequence, but 
coerce the sequence to a list/set/etc. if it's not already a list/set/etc. 
I think one viable approach would be to do the following:

   1. Add a notion of "coercing contracts" whose expressiveness lies 
   between chaperone contracts and impersonator contracts. A coercing contract 
   is allowed to produce a non-equal result, but only in a way that 
   "normalizes" the input: (c (c x)) should be equal to (c x) for any coercing 
   contract c, but (c x) does not have to be equal to x. Many situations that 
   currently disallow impersonator contracts could reasonably allow coercing 
   contracts, including hash/c.
   2. Make it easier to combine define/contract and module boundary 
   contracts. Using just define/contract gives you lousy blame boundaries for 
   clients of your module, but that would be trivially easy to fix if 
   `recontract-out` worked on identifiers bound with define/contract.

Using your path-string? example, this would result in something like this:

(provide (recontract-out read-config-file))
(define path-string/c (coerce/c path-string? string->path))
(define/contract (read-config-file path)
  (-> path-string/c config?)
  (parse-config (file->string path)))

On Monday, March 7, 2022 at 7:56:52 AM UTC-8 david@gmail.com wrote:

> Would this give part of what you're looking for?
>
> #lang racket
>
> (define (my-string-length s)
>   ((or/c (and/c (or/c symbol? string?) (compose1 string-length ~a))
>  (curry raise-arguments-error 'my-string-length "invalid arg" 
> "arg"))
>s))
>
> (my-string-length "foo")
> (my-string-length 'foo)
> (my-string-length 7)
>
>
> It's not something you'd want to write by hand in a lot of places, but it 
> seems an easy target for a macro.
>
>
> On Sun, Mar 6, 2022 at 10:47 AM Alexis King  wrote:
>
>> Hello,
>>
>> As a user of the Racket contract system, I sometimes find myself thinking 
>> about the potential utility of “coercing” or “canonicalizing” contracts. In 
>> Racket programs, we often idiomatically allow values to be provided to a 
>> function in a non-canonical form for the sake of convenience. One example 
>> is the commonly-used path-string? contract, which is morally equivalent 
>> to using path? but allows the caller to omit an explicit use of 
>> string->path. Another example is the commonly-used failure-result/c 
>> contract, which allows the caller to omit wrapping non-procedures in a 
>> thunk.
>>
>> While this idiom does make life easier for one party to the contract, it 
>> ultimately just transfers the burden of canonicalizing the value to the 
>> other party. This is unfortunate, because it results in a duplication of 
>> both logic and work:
>>
>>- 
>>
>>Code to canonicalize the value must be written separately and kept in 
>>sync with the contract, which is error-prone.
>>- 
>>
>>The value ends up being inspected twice: once to determine if it 
>>satisfies the contract, and a second time to convert it to canonical form.
>>
>> (In the nomenclature of a popular blog post I wrote a few years ago, 
>> these contracts are validating, not parsing 
>> .)
>>
>> In theory, it is perfectly possible to implement a canonicalizing 
>> contract using the current contract system. However, such a contract has 
>> several practical downsides:
>>
>>- 
>>
>>It is necessarily an impersonator contract, not a chaperone contract. 
>>This prevents its use in places that demand a chaperone contract, such as 
>>the *key* argument to hash/c.
>>- 
>>
>>It moves actual logic into the contract itself, which means using the 
>>uncontracted value directly is less convenient. This encourages placing 
>> the 
>>contract boundary close to the value’s definition to create a very small 
>>contracted region (e.g. via define/contract), even though blame is 
>>generally more useful when the contract boundary corresponds to a 
>> boundary 
>>between higher-level components (e.g. via contract-out).
>>- 
>>
>>There is no way to write such contracts using the combinators 
>>provided by racket/contract, so they must be implemented via the 
>>lower level make-contract/build-contract-property API. This can be 
>>subtle to use correctly, and it makes it unlikely that contract 
>> violations 
>>made by the contract itself will be blamed properly according to the 
>> “indy” 
>>blame semantics used by ->i.
>>
>> All this is to say that the current contract system clearly discourages 
>> this use of contracts, which suggests this would be considered an abuse of 
>> the contract system. Nevertheless, the coupling between validating values 
>> and converting them to a normal form is so enormously tight that allowing 
>> them to be 

[racket-users] Re: How to discover a struct's interface without Dr Racket?

2021-10-28 Thread jackh...@gmail.com
Are you intending to use the struct procedure names at compile time (such 
as in a macro) or runtime?

On Tuesday, October 26, 2021 at 5:02:46 PM UTC-7 bc.be...@gmail.com wrote:

> I understand why structs are opaque, by default, but I want to discover 
> the public interface of some struct type, that is, a list of the procedures 
> defined by the struct.
>
> Here is an example. Suppose I want to find out all the procedures defined 
> on an instance of the syntax struct
>
> #'42
>
> Dr. Racket shows an expander clicky that shows some formatted information 
> inside the instance :
>
> [image: Screenshot from 2021-10-26 16-51-37.png]
>
> Uncapitializing the names in the display reveals the interface:
>
> (syntax-position #'42) ~~> 790
> (syntax-span #'42) ~~> 2
> (syntax-original? #'42) ~~> #t
>
> etc.
>
> I want to discover those procedure names in my racket program, not 
> manually by visually inspecting graphics in Dr Racket. 
>
> I found this trick for structs that I define:
>
> #lang racket
> (require (for-syntax racket/struct-info))
> (require racket/pretty)
>
> (struct foo (a b))
> (begin-for-syntax
>   (displayln 
>(extract-struct-info
> (syntax-local-value
>  #'foo
>
> ~~>
>
> [image: Screenshot from 2021-10-26 16-59-19.png]
>
> but it doesn't work for the syntax type
>
> (begin-for-syntax
>   (displayln 
>(extract-struct-info
> (syntax-local-value
>  #'syntax
>
> ~~>
>
> [image: Screenshot from 2021-10-26 17-00-33.png]
>
> I'd be grateful for advice and an example of how to get the interface of 
> "syntax" without Dr Racket and without grovelling docs.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/a7d7828e-7114-488c-877e-308ef3c9d068n%40googlegroups.com.


Re: [racket-users] rename-out not working as expected

2021-10-14 Thread jackh...@gmail.com
static-rename compiles down to something totally different, actually. It 
uses the 'inferred-name 

 
syntax property to get the Racket compiler to choose a different name for 
the function at compile time. This is different from `(procedure-rename 
do-something 'do-i)`, which creates a wrapper function around the original. 
The 'inferred-name approach is guaranteed to have no runtime overhead.

On Tuesday, October 12, 2021 at 12:25:15 PM UTC-7 david@gmail.com wrote:

> Okay, good.  Thanks for the library recommendation; I'll probably use that 
> in the future where I need to rename/provide multiple things, but given 
> that there's only one I did this instead in order to avoid having another 
> dependency:
>
> (provide do-it)
> (define do-it (procedure-rename do-something 'do-i))
>
> I suspect I'm reinventing the wheel and that's what static-rename compiles 
> down to.
>
>
> On Tue, Oct 12, 2021 at 3:14 PM 'William J. Bowman' via Racket Users <
> racket...@googlegroups.com> wrote:
>
>> I think this is the expected behaviour of `rename-out`; you might want 
>> this library to change the dynamic displayed name:
>>   https://docs.racket-lang.org/static-rename/index.html
>>
>> --
>> William J. Bowman
>>
>> On Tue, Oct 12, 2021 at 03:07:13PM -0400, David Storrs wrote:
>> > ---
>> > ; test.rkt
>> > #lang racket
>> > (define (do-something) "ok")
>> > (provide do-something)
>> > 
>> > ; test2.rkt
>> > #lang racket
>> > (require "test.rkt")
>> > (provide (rename-out [do-something do-it]))
>> > 
>> > #lang racket
>> > (require "test2.rkt")
>> > do-it
>> > ---
>> > 
>> > The printed value is # although I was expecting
>> > #.  Have I done something wrong or simply misunderstood
>> > how rename-out works?
>> > 
>> > -- 
>> > You received this message because you are subscribed to the Google 
>> Groups "Racket Users" group.
>> > To unsubscribe from this group and stop receiving emails from it, send 
>> an email to racket-users...@googlegroups.com.
>> > To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/racket-users/CAE8gKodiRBWPK5MfgYnOi_V%2B%3DwwFzBxtQK1qV2Mj-zPuHEXn9g%40mail.gmail.com
>> .
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Racket Users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to racket-users...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/racket-users/YWXekUFzaEkaitiB%40williamjbowman.com
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/0dc52c9c-0b8a-462b-94a3-0f126809469dn%40googlegroups.com.


Re: [racket-users] Rationale for package structure

2021-10-14 Thread jackh...@gmail.com
I don't bother with the splitting because it's a *lot* of maintenance 
headache for little gain. My opinion is that we should take the collective 
effort we've poured into splitting packages and instead direct it at 
improving the compiler and package system to do a better job of automating 
this process.

On Sunday, October 10, 2021 at 9:44:03 AM UTC-7 samdph...@gmail.com wrote:

> The --binary flag only works for the current release with the default 
> catalog iirc.
>
> Cheers,
> Sam
>
> On Sat, Oct 9, 2021, 11:58 Sorawee Porncharoenwase  
> wrote:
>
>> I think it's so that `raco pkg install mypkg-lib` won't install 
>> `racket-doc` if you use Minimal Racket?
>>
>> If you don't split `mypkg` to `mypkg-lib` and `mypkg-doc`, but specify 
>> `deps` and `build-deps` correctly, `raco pkg install --binary mypkg` won't 
>> pull in `racket-doc` either. I don't know when this feature was added 
>> though. Perhaps, it could be that the package splitting convention predates 
>> the feature, and the convention persists.
>>
>> On Sat, Oct 9, 2021 at 10:58 AM 'Joel Dueck' via Racket Users <
>> racket...@googlegroups.com> wrote:
>>
>>> I’ve always used the single collection format [1] in my packages.
>>>
>>> However, I see a lot of package authors will use a multi-collection 
>>> format and split the library, documentation and maybe tests out into 
>>> separate collections.
>>>
>>> What are the benefits of splitting the main library and its 
>>> documentation into separate collections?
>>>
>>> [1]: 
>>> https://docs.racket-lang.org/pkg/Package_Concepts.html#%28part._concept~3amulti-collection%29
>>>
>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "Racket Users" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to racket-users...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/racket-users/6ea9f50e-0d4f-4800-bc17-d31979a614cfn%40googlegroups.com
>>>  
>>> 
>>> .
>>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Racket Users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to racket-users...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/racket-users/CADcuegs%3D-YZKaTSmPxreNekuUyxcyMG6AOSzxwnkCnr_8jBkgg%40mail.gmail.com
>>  
>> 
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/b44536f8-d271-461a-9cb9-17b0da8625efn%40googlegroups.com.


Re: [racket-users] Re: Escape continuations for fussy code

2021-10-02 Thread jackh...@gmail.com
Here's my solution:

(define/guard (f x)
  (guard (foo? x) else
#false)
  (define y (bar x))
  (define z (jazz x y))
  (guard (loopy? z) else
#false)
  (define a (yowza z))
  (guard (string? a) else
(error 'ugh))
  (define b (bonkers a))
  (guard (number? (hoop x b)) else
(error 'um))
  (define ...))

It uses a `guard` macro I wrote and talked about in this thread 
.
On Friday, October 1, 2021 at 12:53:25 PM UTC-7 hen...@topoi.pooq.com wrote:

> On Fri, Oct 01, 2021 at 02:32:52PM -0400, David Storrs wrote:
> > On Fri, Oct 1, 2021 at 11:58 AM Hendrik Boom  
> wrote:
> > 
> > > On Fri, Oct 01, 2021 at 02:22:14PM +, Jesse Alama wrote:
> > > > Hello,
> > > >
> > > > Have you ever wished you could do a C-style return in the middle
> > > > of a block of Racket code? When you're in the heat of things with
> > > > a complicated problem where input values need a fair amount of
> > > > multi-stage extraction and validation, using cond quickly pulls
> > > > code to the right. My procedure is:
> > > >
> > > > * cond/case. In each branch:
> > > > * Define some new values safe in the knowledge of where you are
> > > > (extract) and perhaps check them, if necessasry (validate)
> > > > * Make sure you have an else branch.
> > > > * return to 1 and repeat as many times as necessary.
> > > >
> > > > The result:
> > > >
> > > > (cond [(foo? x)
> > > > (define y (bar x))
> > > > (define z (jazz x y))
> > > > (cond [(loopy? z)
> > > > (define a (yowza z))
> > > > (cond [(string? a)
> > > > (define b (bonkers a))
> > > > (cond [(number? (hoop x b))
> > > > (define ...)]
> > > > [else
> > > > (error 'um)])]
> > > > [else
> > > > (error 'ugh)])]
> > > > [else #f])]
> > > > [else #f])
> > >
> > >
> > I'm presuming that this code should either return #f, return a calculated
> > value, or raise an exception. If so, here's a version that runs in plain
> > racket that I find pretty easy to read. It has the advantage that the
> > 'return #f' parts aren't way far away from what causes them.
> > 
> > (with-handlers ([false? identity] ; return #f
> > [any/c raise]) ; re-raise everything else
> > (let* ([x (if (foo? x)
> > x
> > (raise #f))]
> > [z (jazz x (bar x))]
> > [a (if (loopy? z)
> > (yowza z)
> > (raise #f))]
> > [b (if (string? a)
> > (bonkers a)
> > (error 'ugh))])
> > (if (number? (hoop x b))
> > 'all-good
> > (error 'um
>
> Yes. But different semantics if bar, yowza, and bonkers have side effects.
> If they don't, they're quite equivalent.
>
> -- hendrik
>
> > 
> > If instead you want to return the exn that comes from error instead of
> > re-raising it then you can do that by removing the false? clause from the
> > with-handlers. NOTE: You should re-raise exn:break since otherwise the
> > user cannot ^C the program.
> > 
> > (with-handlers ([exn:break? raise]
> > [any/c identity])
> > ...put the let* code here...)
> > 
> > -- 
> > You received this message because you are subscribed to the Google 
> Groups "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send 
> an email to racket-users...@googlegroups.com.
> > To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/CAE8gKodxas7jtze%2BttcFA%2BG0ATKUFZD3rhK%2B%3Dn2U1md1zQPJSg%40mail.gmail.com
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/262c0b9d-6d51-4e03-adcf-0efa3fb76f61n%40googlegroups.com.


Re: [racket-users] New module log-bracketed; should probably be something else

2021-09-23 Thread jackh...@gmail.com
This looks quite a bit like you're trying to implement tracing, which is 
like logging, but instead of emitting messages associated with *points* in 
time, you emit messages for *ranges* of time. Rust has an excellent library 
 for tracing. Perhaps that will 
provide some good inspiration?

On Friday, September 3, 2021 at 8:30:18 AM UTC-7 david@gmail.com wrote:

> On Thu, Sep 2, 2021 at 5:32 PM Sorawee Porncharoenwase <
> sorawe...@gmail.com> wrote:
>
>> Thoughts:
>>
>>- Perhaps the logger should be optional. The default value would be 
>>(current-logger). 
>>- The event name (like on-complete) could also be optional. The 
>>default would be the source location of the macro invocation site 
>>- Instead of “time: ~a”, I think it would be nice to support many 
>>“pairs”, which are formatted like raise-arguments-error. 
>>
>> Example:
>>
>> (define (on-complete x)
>>   (log-test-debug "I'm in on-complete")
>>   x)
>>
>> (with-log ()
>>   1)
>>
>> (with-log (#:logger test-debug
>>#:msg "on-complete"
>>["time" (current-seconds)])
>>   (on-complete (person 'bob)))
>>
>> would output:
>>
>> test: entering test.rkt:5:1
>> test: exiting test.rkt:5:1
>> result: 1
>> 1
>> test: entering on-complete
>> time: 123
>> test: I'm in on-complete
>> test: exiting on-complete
>> time: 124
>> result: (person 'bob)
>> (person 'bob)
>>
>>
>>
> First of all, thank you.  I like the idea of the event name being optional 
> and the logger defaulting but I'm not keen on the syntax.  It's very 
> verbose for something that might occasionally be wrapped around a single 
> line of code. The raise-arguments-error formatting would be a nice default 
> but I prefer to give the option to use a format string if you want 
> something different.
>
>
>> On Thu, Sep 2, 2021 at 2:06 PM Martin DeMello  
>> wrote:
>>
>>> I do like the second form better, especially since the actual code being 
>>> run is not obscured by simply being the last argument to a long log 
>>> function.
>>>
>>
> Cool.  I'll move towards that.
>
>
>>> martin
>>>
>>> On Thu, Sep 2, 2021 at 1:55 PM David Storrs  wrote:
>>>
 I often find that for debugging I want to see a log message saying "I'm 
 about to do X" followed by X followed by "I'm done with X" and I want it 
 to 
 return the result of X.

 I wrote this macro and posted it to the package server:  
 https://pkgs.racket-lang.org/package/log-bracketed

 In retrospect, the syntax is bad and I should change it.  Can anyone 
 suggest something better?

   (define (on-complete x) (log-test-debug "entering on-complete") x)
   (struct person (name) #:transparent)

   (log-bracketed test-debug "on-complete" "time: ~a" (current-seconds) 
 (on-complete (person 'bob)))
   (log-bracketed test-debug "on-complete" "" "no user-specified logging 
 information")

 Spits out:


 test: about to on-complete. time: 1630611613
 test: entering on-complete
 test: after on-complete. time: 1630611613. result: (person 'bob)
 (person 'bob)
 test: about to on-complete
 test: after on-complete. result: "no user-specified logging information"
 "no user-specified logging information"


 The problem is that this looks like it's a simple logging message when 
 in fact it's real code that should not be ignored.  I'm trying to think of 
 a better way to do it...maybe something like this?:

   (with-bracketing-logs ([test-debug "on-complete" "time: ~a" 
 (current-seconds)])

  (on-complete (person 'bob))



 -- 
 You received this message because you are subscribed to the Google 
 Groups "Racket Users" group.
 To unsubscribe from this group and stop receiving emails from it, send 
 an email to racket-users...@googlegroups.com.
 To view this discussion on the web visit 
 https://groups.google.com/d/msgid/racket-users/CAE8gKocZha-NpiFAAKT1c8QTG3MDFRnvxCD4T0P269EncZW3KQ%40mail.gmail.com
  
 
 .

>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "Racket Users" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to racket-users...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/racket-users/CAFrFfuEqt1NVjE2Ft1JVArvWnKUBvK7jPVoLqPhYCd-dB00A3Q%40mail.gmail.com
>>>  
>>> 
>>> .
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe 

[racket-users] Re: Re-entrant parameterize modification isolation when using shift/reset

2021-07-29 Thread jackh...@gmail.com
I don't fully follow the example you gave because I'm not super familiar 
with shift/reset, but would using continuation marks directly instead of 
parameters work for your use case? Continuation marks work like what you 
described, where data is stored directly on the stack rather than in a 
thread cell pointed to by the stack.

On Sunday, July 25, 2021 at 10:35:00 AM UTC-7 greg@gmail.com wrote:

> I'm using dynamic binding while also using delimited control operators 
> such as shift and reset.  When shift captures the context of a 
> `parameterize`, I'd like to be able to resume that continuation in the same 
> context multiple times without observing modifications caused by other 
> resumptions.
>
> I was surprised that subsequent re-entries can observe modifications from 
> the earlier ones, since my mental model of dynamic parameters was that 
> their values were retrieved from a fresh dynamic calling context, whose 
> frames are copied each time the delimited continuation is invoked.  But it 
> looks like dynamic parameters actually rely on a shared mutable cell, in 
> this case a thread cell.
>
> Knowing this, I have a strange workaround using a wrapping thread to force 
> a distinct thread cell to be created for each resumption, providing 
> isolation.  Is there a better way to do this?
>
> I'm also interested in the reasons behind the current design.  Is there a 
> downside to storing parameter bindings directly on the stack, rather than 
> in a thread cell pointed to by the stack?
>
>
> Here is an example, including a demonstration of the workaround:
>
> ```
> #lang racket/base
> (require racket/control)
>
> (define P (make-parameter #f))
> (define (show) (displayln (P)))
> (define (inc) (P (+ 1 (P
>
> (define (re-enter k)
>   (define result (void))
>   (define t (thread
>   (lambda ()
> (set! result (k (void))
>   (thread-wait t)
>   result)
>
>
> (define K (reset (parameterize ((P 0))
>(show)
>(inc)
>(shift k k)
>(show)
>(inc)
>(P
>
> ;; The behavior that surprised me:
> (displayln "without threads:")
> (K) ; 2
> (K) ; 3
> (K) ; 4
>
> ;; The behavior I would like:
> (displayln "with threads:")
> (re-enter K) ; 5
> (re-enter K) ; 5
> (re-enter K) ; 5
> ```
>
>
> Program output:
>
> 0
> without threads:
> 1
> 2
> 2
> 3
> 3
> 4
> with threads:
> 4
> 5
> 4
> 5
> 4
> 5
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/b0d6f680-7c69-4b41-b21e-8744ee997e78n%40googlegroups.com.


Re: [racket-users] Speeding up the conversion of flvectors to string

2021-06-27 Thread jackh...@gmail.com
Anyone got an implementation of a mutable StringBuilder-like object? I 
could use it in Rebellion's implementation of `into-string` which currently 
isn't quadratic, but it definitely has the allocation problem.

On Sunday, June 27, 2021 at 11:36:14 AM UTC-7 bogdan wrote:

> While I think the complexity piece is important, I feel like it's worth
> pointing out just how much more expensive the allocation -- and its
> ramifications, like the resulting GC pressure and CPU cache misses -- is
> than one might think. Here's a quadratic version of the code that
> avoids allocations:
>
> #lang racket
>
> (require racket/flonum)
>
> (define (xy->string x y)
> (string-append
> (~r x #:precision 1) ","
> (~r y #:precision 1)))
>
> (define len 0)
> (define dst (make-string 500))
> (define (string-append! b)
> (string-copy! dst 0 dst 0 len) ;; intentionally performing pointless work 
> to be n^2
> (string-copy! dst len b)
> (set! len (+ len (string-length b
>
> (define (xy-vectors->string x-vec y-vec)
> (for ((x (in-flvector x-vec))
> (y (in-flvector y-vec)))
> (string-append! (xy->string x y))
> (string-append! " ")))
>
> (time
> (let ([x (make-flvector 10)]
> [y (make-flvector 10)])
> (xy-vectors->string x y)))
>
> On my machine (running Racket CS 8.1), this is faster than the
> `call-with-output-string` version I posted earlier by about 50ms.
>
>
> Jens Axel Søgaard writes:
>
> > Den søn. 27. jun. 2021 kl. 18.58 skrev Alessandro Motta <
> amot...@gmail.com
> >>:
> >
> >> I also like Jens' code for its pure functional elegance. I'm surprised
> >> that building up a long list of short strings before joining them is so
> >> much faster. After all, isn't the final `string-join` essentially doing
> >> what the original code snipped did? (Clearly not! I will have a look at
> >> the implementation.)
> >>
> >
> > The following is the same answer as Robby's, but fills in some details.
> > I wrote this mainly because I couldn't find a web-page with the 
> explanation.
> >
> > Let's say we have two strings a and b of lengths m and n respectively.
> >
> > How much work must (string-append a b) do?
> >
> > Conceptually the following steps need to be done:
> > 1. Allocate a new string c of length m+n.
> > 2. Copy the string a into c.
> > 3. Copy the string b into c.
> >
> > This means that the time (work) needed to append the strings a and b are
> > proportional to m+n.
> >
> > How much work is done here?
> >
> > (string-append "x" (string-append "y" (string-append "z" "")))
> >
> > First (string-append "z" "w") takes time 1+0=1 with the result "z".
> > Then (string-append "y" (string-append "z" "")) or (string-append "y" 
> "z")
> > takes time 1+1=2 with the result "yz".
> > Then (string-append "x" (string-append "y" (string-append "z" ""))) or
> > (string-append "x" "yz") takes time 1+2 = 3 with result "xyz".
> > In total we have used time 1+2+3 =6.
> >
> > We see that if we 3 times use string-append to add strings of length 1,
> > then we use time 1+2+3=6.
> > In general, if we n times use string-append to add strings of length 1,
> > then we use time 1+2+3+...+n.
> > The last sum is more or less n^2. See [1].
> >
> > The same thing happens in your loop, where you repeatedly use 
> string-append
> > to append a small string.
> > The length of the small string is no longer 1, but the same happens - and
> > the time used by the
> > loop is proportional to n^2.
> >
> >
> > Now suppose we have a list of the strings to append
> > (list "x" "y" "z")
> > and we need to append them. How much work is there now?
> >
> > Well, first we can calculate the length of the result 1+1+1 = 3.
> > Then we allocate a new string of length 3. Then each individual
> > string is copied and that takes time 1+1+1=3.
> >
> > Here, each string is only copied once. For comparison in the loop version
> > the string z is copied multiple times.
> >
> >
> > But wait - why does a loop that uses cons multiple times to build up
> > a list not have the same problem?
> >
> > Because in (cons x xs) the existing list xs isn't copied.
> > The steps are
> > 1. a new pair with two cells (the car and the cdr) are allocated
> > 2. the contents of the car is set to x
> > 3. the contents of the cdr is set to xs.
> >
> > This always takes the same amount of time, no matter how long the list xs
> > is.
> > This means that the time used by cons is constant (that is, proportional 
> to
> > 1).
> >
> > Note: This phenomenon that using string-append in a loop is not a Racket
> > only problem.
> > It is a common pitfall in many languages.
> >
> >
> >
> > [1] Remember the famous story of Gauss as a child that calculated
> > 1+2+...1000 ?
> > https://www.youtube.com/watch?v=Dd81F6-Ar_0
> >
> >
> > /Jens Axel - https://racket-stories.com
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To 

[racket-users] Re: stream leaking memory #2870

2021-04-28 Thread jackh...@gmail.com
Thankful comments on closed issues are definitely allowed and quite 
appreciated. Mailing list posts work too though.

On Tuesday, April 27, 2021 at 8:16:38 AM UTC-7 jos.koot wrote:

> Because the issue is closed I express my thanks to Matthew here.
>
> I am not sure it is allowed to add thanks to a closed issue.
>
> Jos
>
>  
>
>  
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/178e57f1-e810-43d3-9981-52cb1af561b9n%40googlegroups.com.


Re: [racket-users] How to recover whitespace from syntax->string

2021-04-10 Thread jackh...@gmail.com
I had to build something for this 
 
in my Resyntax project. My takeaways were:

   - There's no substitute for just reading the file. If you have a 
   `syntax-original?` subform, you can use the srcloc information to read the 
   exact original text that was in the source file. This not only preserves 
   whitespace more accurately than `syntax->string`, it also preserves 
   comments, which is something that `syntax->string` fundamentally cannot do.
   - For non-original syntax, such as that synthetic "comments" bit you're 
   inserting programmatically, just ignore the source locations completely. 
   They refer to the source location of where it occurs in your 
   program-manipulating-program, which is completely unrelated to the 
   positions of the original syntax. The `syntax->string` form doesn't handle 
   it well when some subforms are original and some aren't, or when subforms 
   are from different sources.
   - It's handy to have a way to communicate explicit formatting. I did 
   this by having a special NEWLINE form that my code could shove into the 
   syntax object before rendering it to a string, to tell the formatter where 
   to insert line breaks.
   - If you just rely on `syntax-original?` to preserve 
   whitespace/comments, you'll miss the whitespace and comments *between* 
   original syntax objects. I dealt with this by having an `(ORIGINAL-SPLICE 
   original-syntax ...)` form that I used to tell the formatter that not only 
   are all of these syntax objects original, but the entire sequence is 
   unchanged from the input program. That allows the formatter to copy the 
   source file text from the start of the first syntax object all the way to 
   the end of the last one, preserving any whitespace and comments in between 
   them.
   

On Friday, April 9, 2021 at 4:22:31 PM UTC-7 Jeff Henrikson wrote:

> It turns out that I have more trouble with printing whitespace from 
> syntax.  Consider this:
>
> (require racket)
> (require syntax/to-string)
>
> (define (syntax-on-lines-v1 xs)
>   (define (iter fin ys)
> (let ((y (read-syntax "" fin)))
>   (if (eof-object? y)
>   (reverse ys)
>   (iter fin (cons y ys)
>   (if (null? xs)
>   '()
>   (let* ((fout (open-output-string))
>  (_ (for* ((x xs))
>   (writeln x fout)))
>  (_ (close-output-port fout))
>  (fin (open-input-string (get-output-string fout
> (port-count-lines! fin)
> (iter fin '()
>
> The basic case works:
>
> ;; ex1
> (let* ((xs '("collected" "from" "separate" "lines"))
>(ys (syntax-on-lines xs)))
>   (syntax->string 
>#`(#,@ys)))
> ;; "\"collected\"\n\"from\"\n\"separate\"\n\"lines\""
>
> But I need to decorate a number of constant items, such as:
>
> ;; ex2
> (let* ((xs '("collected" "from" "separate" "lines"))
>(ys (syntax-on-lines xs)))
>   (syntax->string 
>#`(comment #,@ys)))
> ;; "comment\"collected\"\"from\"\"separate\"\"lines\""
>
> In ex2, the loss of line breaks seems to stem from lack of srcloc info on 
> the first token.  However, I don't understand just what's necessary to keep 
> things moving along.  If I populate the first token only with 
> quasisyntax/loc as follows, I get my EOLs:
>
> ;; ex3
> (let* ((xs '("collected" "from" "separate" "lines"))
>(ys (syntax-on-lines xs))
>(zs (cons (quasisyntax/loc (car ys) "comments") ys)))
>   (syntax->string 
>#`(#,@zs)))
> ;; "\"comments\"\"collected\"\n\"from\"\n\"separate\"\n\"lines\""
>
> But that's quite inconvenient if I have a bunch of stuff to decorate.  If 
> I try to do the more convenient outside position for quasisyntax/loc, my 
> EOL data seems to get overwritten:
>
> ;; ex4
> (let* ((xs '("collected" "from" "separate" "lines"))
>(ys (syntax-on-lines xs)))
>   (syntax->string (quasisyntax/loc (car ys) ("comments" #,@ys
> ;; "\"comments\"\"collected\"\"from\"\"separate\"\"lines\""
>
> Is there a way to do something like ex4, where I can add a number of new 
> constant tokens, but without overwriting the EOL data?
>
> Thanks in advance,
>
>
> Jeff Henrikson
>
>
> On 4/9/21 9:57 AM, Jeff Henrikson wrote:
>
> Laurent,
>
> Thank you very much.  It probably would have taken me a long time on my 
> own to think of the possibility that the port was at fault.
>
>
> Jeff
>
>
> On 4/9/21 4:29 AM, Laurent wrote:
>
> You need to enable line/character counting with `port-count-lines!`:
>
> #lang racket
> (require syntax/to-string)
>
> (define in (open-input-string "(comment\n  \"hello world\"\n  line)"))
> (port-count-lines! in)
> (syntax->string (read-syntax "mystring" in))
>
> ; -> "comment\n \"hello world\"\n line"
>
> On Fri, Apr 9, 2021 at 2:10 AM Jeff Henrikson  wrote:
>
>> Racket users,
>>
>> I’m trying to read a scheme file, decorate a bit of window dressing 
>> around the edges, and write the expressions to a new 

[racket-users] Re: mixfix and racket 2

2021-03-23 Thread jackh...@gmail.com
Honu's enforestation is approximately this. See 
https://www.cs.utah.edu/plt/publications/gpce12-rf.pdf. There's been some 
discussion about whether to base rhombus on a similar approach.
On Tuesday, March 23, 2021 at 8:59:50 AM UTC-7 Roger Keays wrote:

> From racket-news [1]:
>
> mixfix (pkg/src) library allows users to define and use mixfix operators 
> in Racket, by Sorawee Porncharoenwase.
>
> From the mixfix docs [2]:
>
> > (define-mixfix-rule (c {~datum ?} t {~datum :} e)
> (if c t e))
> > (#true ? 1 : 2)
> 1
>
> This is what I expected to be able to do when I first started 
> experimenting with various LISPs and Schemes. Supporting only prefix macros 
> seemed like a bit of limitation to me. If mixfix macros were supported out 
> of the box rather than hacking #%app, it would be easier to combine syntax 
> libraries. Possible for Racket 2?
>
> [1] https://racket-news.com/2021/03/racket-news-issue-48.html
> [2] https://docs.racket-lang.org/mixfix/
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/198c4676-08de-4803-9a8b-719d9c298159n%40googlegroups.com.


[racket-users] Re: When are rackunit tests delayed? (different between 7.8 and 8)

2021-02-25 Thread jackh...@gmail.com
The test-suite semantics in rackunit are complex, under-specified, and 
quite brittle. I recommend avoiding them entirely and sticking entirely to 
test cases and test-begin.

On Monday, February 22, 2021 at 10:19:04 PM UTC-8 William J. Bowman wrote:

> Below is an example that behaves "correctly", as in all tests run and are
> counted as failured or errors correctly, in Racket 7.8, but which crashes 
> in
> Racket 8.
>
> > #lang racket
> > 
> > (require
> > rackunit
> > rackunit/log)
> > 
> > (define (suite1)
> > (test-suite
> > ""
> > (test-begin
> > (check-not-equal? (error "actual") (error "expected")
> > 
> > (define (suite2)
> > (test-suite
> > ""
> > (check-not-equal? (error "actual") (error "expected"
> > 
> > (module+ test
> > (require rackunit/text-ui)
> > 
> > ;; Correctly counts the tests as errors in 7.8 and 8.0
> > (check-pred
> > integer?
> > (run-tests (suite1)))
> > 
> > ;; Counts the tests as errors in 7.8, but crashes in 8.0
> > (check-pred
> > integer?
> > (run-tests (suite2)))
> >
> > ;; Gets run in 7.8, but not in 8.0
> > (check-equal? 0 0))
>
> This has something to do with when test-suite delays a test, which seems
> inconsistent across the Racket versions.
> I'm not sure whether the problem was some undefined behaviour in 
> test-suite or
> not.
>
> I'm a bit confused about the semantics of test-suites and tests, since the
> documentation claims a test (unlike a check) is delayed, yet test-case and
> test-begin do not delay tests, while test-suite does produce a delayed 
> suite of
> tests.
> However, test-begin DOES seem to delay a test in the context of a 
> test-suite.
>
> I'd appreciate any insight.
>
> --
> William J. Bowman
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/73510d26-7405-4c0a-a0e3-1b06f77f3576n%40googlegroups.com.


Re: [racket-users] the future of #lang web-server

2021-02-25 Thread jackh...@gmail.com
Could you cryptographically sign the serialized form or something like that?

On Monday, February 22, 2021 at 8:59:29 AM UTC-8 jay.mc...@gmail.com wrote:

> On Sun, Feb 21, 2021 at 2:35 PM je...@lisp.sh  wrote:
> >
> > #lang web-server is brilliant. This #lang is, in my view, a really 
> excellent example of Racket's take on language-oriented programming. I find 
> that the performance of continuations is just fine, given my limited use of 
> them, and after a while you get used to the limitations and just program 
> around them.
>
> Thanks, a lot of people contributed a ton to it, specifically: Greg
> Pettyjohn, John Clements, Joe Marshall, Shriram Krishnamurthi,
> Matthias Felleisen.
>
> >
> > One thing that always bothers me about #lang web-server, though, is that 
> there are a lot of provisos in the documentation. I'm talking about section 
> 3.2, "Usage Considerations", of 
> https://docs.racket-lang.org/web-server/stateless.html, in the part after 
> "However, there are some considerations you must make." Here a couple of 
> questions:
> >
> > + " [#lang web-server] will create an immense number of lambdas and 
> structures your program did not normally contain. The performance 
> implication of this has not been studied with Racket."
> >
> > This seems to me like an interesting research question. Has this 
> question been taken up? I've tried taking a look on Google Scholar for any 
> follow-up. I looked at citations of Jay's "Automatically RESTful web 
> applications" and "The two-state solution: native and serializable 
> continuations accord", but nothing stuck out to me (...which is not to say 
> that there may have missed something).
>
>
> I never did any more research about this. I think you could take the
> traditional Scheme benchmarks ---
>
> https://github.com/racket/racket/tree/master/pkgs/racket-benchmarks/tests/racket/benchmarks/common
> --- and add `#lang web-server` to the top and see what happens.
>
> >
> > + Some limitations of #lang web-server seem don't seem obviously 
> necessary, at least to someone who's not very familiar with the precise 
> details of the underlying program transformations. You get used to them, 
> but you wonder if there's some accessible world in which they work. For 
> example: "You may not use parameterize, because parameterizations are not 
> serializable." Is that inherently so (that is, there's no way around that, 
> no matter how clever you tweak the program transformations on which #lang 
> web-server rests), or is that just a conequence of the particular approach 
> taken (maybe it's possible, but no one has done it yet). Has there been any 
> fresh thinking about these limitations?
>
> In some sense, everything is possible, because we can just change the
> way the VM works... the existing `#lang web-server` is designed to
> never require modifications down there. In the case of `parameterize`,
> the problem is a matter of security. Consider the following program:
>
> ```
> #lang racket
> (define p (make-parameter #t))
> (define (launch-the-missiles!)
> (when (p) .))
> (define (run-code-downloaded-from-youtube f)
> (parameterize ([p #f]) (f)))
> ```
>
> We don't want the code from YouTube to be able to launch the missiles.
> Suppose that parameterizations were serializeable, then the YouTube
> code could be something like:
>
> ```
> (lambda ()
> (call-with-parameterization
> (read (with-input-string (hack-the-planet (with-output-to-string
> (lambda () (write (current-parameterization)
> launch-the-missiles!))
> ```
>
> where `hack-the-planet` changes the `#f` to `#t`. That's why you can't
> inspect parameterizations or enumerate the keys in a continuation mark
> set.
>
> In general, all of the limitations of `#lang web-server` are because
> of things like this.
>
> Jay
>
> --
> Jay McCarthy
> Associate Professor @ CS @ UMass Lowell
> http://jeapostrophe.github.io
> Vincit qui se vincit.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/0854aacf-b390-4bc7-8b7a-6b114c19bb5cn%40googlegroups.com.


Re: [racket-users] Sticky scrollable nav bar in docs

2021-02-19 Thread jackh...@gmail.com
This is great! Definitely send a PR for this.

On Thursday, February 18, 2021 at 4:56:23 PM UTC-8 Ben Greenman wrote:

> "sticky" looks worse to me on that example page --- I have to scroll
> to the bottom of all the set docs before I can read the navbar
>
> On 2/18/21, Yury Bulka  wrote:
> > I agree this is a useful improvement. I would consider using "position:
> > sticky" instead of "position: fixed" as that is generally less
> > "intrusive" to the layout and doesn't create a need for a second scroll
> > bar (the element would scroll as needed with the main scrollbar, but
> > still be sticky in the sense that it would keep itself within the
> > viewport).
> >
> > --
> > Yury Bulka
> > https://mamot.fr/@setthemfree
> > #NotOnFacebook
> >
> >
> >
> > Sam Tobin-Hochstadt  writes:
> >
> >> This seems like it would be a nice addition. I think starting with a
> >> PR is the right place to begin.
> >>
> >> Sam
> >>
> >> On Wed, Feb 17, 2021 at 7:01 PM 'William J. Bowman' via Racket Users
> >>  wrote:
> >>>
> >>> One of my students asked about making the Racket docs navbar sticky and
> >>> scrollable, to help when navigating very long docs pages. I made a 
> quick
> >>> hack and deployed it here:
> >>> https://www.students.cs.ubc.ca/~cs-411/docs/reference/sets.html
> >>>
> >>> Personally I've found it very useful. Would this change make sense for
> >>> the Racket docs generally? (With some polish by someone who is better 
> at
> >>> UX than me?)
> >>>
> >>> To implement it, I just replaced `doc-site.css` with the following
> >>>
> >>> .navsettop {
> >>> position: fixed;
> >>> z-index: 1;
> >>> background: #a7b0be;
> >>> height: auto;
> >>> }
> >>>
> >>>
> >>> .tocset {
> >>> position: fixed;
> >>> overflow-y: scroll;
> >>> height: 88%;
> >>> }
> >>>
> >>> --
> >>> William J. Bowman
> >>>
> >>> --
> >>> You received this message because you are subscribed to the Google 
> Groups
> >>> "Racket Users" group.
> >>> To unsubscribe from this group and stop receiving emails from it, send 
> an
> >>> email to racket-users...@googlegroups.com.
> >>> To view this discussion on the web visit
> >>> 
> https://groups.google.com/d/msgid/racket-users/YC2uQ3BJIsMJTsMP%40williamjbowman.com
> .
> >
> > --
> > You received this message because you are subscribed to the Google Groups
> > "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send an
> > email to racket-users...@googlegroups.com.
> > To view this discussion on the web visit
> > 
> https://groups.google.com/d/msgid/racket-users/87zh01ht4j.fsf%40privacyrequired.com
> .
> >
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/2fbd13ab-3e93-4145-a384-89f5e6da0839n%40googlegroups.com.


[racket-users] Re: Looking for idiomatic way to represent very similar but different data types

2021-02-01 Thread jackh...@gmail.com
rators on my data types such that they 
>>> accept arbitrary amounts of arguments and provide the map for other uses.
>>>
>>> So that's why the vector (in the Racket sense) is the most simple option 
>>> in that respect, since I can trivially do:
>>>
>>> (define (sum-vector v)
>>> (apply + (vector->list v)))
>>>
>>> (define (vector+ . vs)
>>> (apply vector-map + vs)) 
>>>
>>> (define (vector-i v)
>>> (vector-ref v 0))
>>> ;; and so on
>>>
>>> The only think I don't get there are my wanted datatypes and associated 
>>> predicates, since vectors, points, and colors would all be Racket vectors.
>>>
>>> I could almost do structs with a fourth optional argument that holds a 
>>> Racket vector that never gets used explicitly by the "user" and build 
>>> helper functions to properly update it, which is then used to build all the 
>>> operator and other such functions.
>>>
>>> If I just do structs as I originally notated, how do you suggest I 
>>> implement things like vector+ to take in arbitrary amounts of arguments?
>>>  
>>>
>>> On Monday, February 1, 2021 at 12:48:19 AM UTC-6 jackh...@gmail.com 
>>> wrote:
>>>
>>>> I'd suggest just going with the structs and making them transparent. 
>>>> It's only three structs and only with a handful of fields, abstracting 
>>>> over 
>>>> them with map and fold doesn't seem worth the added complexity IMO. But if 
>>>> you'd really like to map and fold over structs, I highly recommend using 
>>>> macros, `syntax-parse` and the struct-id 
>>>> <https://docs.racket-lang.org/syntax-classes/index.html?q=struct-id#%28form._%28%28lib._syntax%2Fparse%2Fclass%2Fstruct-id..rkt%29._struct-id%29%29>
>>>>  
>>>> syntax class to do so:
>>>>
>>>> (require (for-syntax syntax/parse/class/struct-id)
>>>>  syntax/parse/define)
>>>>
>>>> (define-simple-macro (struct-map type:struct-id instance-expr:expr 
>>>> map-function-expr:expr)
>>>>   (let ([map-function map-function-expr]
>>>> [instance instance-expr])
>>>> (type.constructor-id (map-function (type.accessor-id instance)) 
>>>> ...)))
>>>>
>>>> (struct point (x y z) #:transparent)
>>>>
>>>> ;; Outputs (point 2 3 4)
>>>> (struct-map point (point 1 2 3) add1)
>>>> On Sunday, January 31, 2021 at 4:20:03 PM UTC-8 making-a-racket wrote:
>>>>
>>>>> Hello. I have a project where I am needing to represent vectors (in 
>>>>> the mathematical sense), points, and colors. Both the vectors and points 
>>>>> will be 3D. I'm having trouble knowing what's an idiomatic way to 
>>>>> represent 
>>>>> and interact with data types that are similar but different.
>>>>>
>>>>> In general, I could simply all represent them with a list or vector 
>>>>> (in the Racket sense). So I could have:
>>>>>
>>>>> (define (vector i j k) #(i j k))
>>>>> (define (point x y z) #(x y z))
>>>>>
>>>>> Then I could readily use the existing vector functions, such as 
>>>>> vector-map without having to define my own. But I don't super like this 
>>>>> because I have to define my own accessor functions like vector-i and 
>>>>> point-y and also don't get predicates like vector? for free.
>>>>>
>>>>> Another way is that I could use structs, but then I'm stuck 
>>>>> implementing things myself and across the structs. To avoid the latter 
>>>>> point, I could use pattern matching. So something like:
>>>>>
>>>>> (struct vector (i j k))
>>>>> (struct point (x y z))
>>>>>
>>>>> (define (tuple-map proc tuple)
>>>>>   (match tuple
>>>>> [(struct vector (i j k)) (vector (proc (vector-i tuple))
>>>>>  (proc (vector-j tuple))
>>>>>  (proc (vector-k tuple)))]
>>>>> [(struct point (x y z)) (point (proc (point-x tuple))
>>>>>(proc (point-y tuple))
>>>>>(proc (point-z tuple)))]
>>>>> [(struct color (r g b)) (color (proc (color-r tuple))
>&

[racket-users] Re: Looking for idiomatic way to represent very similar but different data types

2021-01-31 Thread jackh...@gmail.com
I'd suggest just going with the structs and making them transparent. It's 
only three structs and only with a handful of fields, abstracting over them 
with map and fold doesn't seem worth the added complexity IMO. But if you'd 
really like to map and fold over structs, I highly recommend using macros, 
`syntax-parse` and the struct-id 

 
syntax class to do so:

(require (for-syntax syntax/parse/class/struct-id)
 syntax/parse/define)

(define-simple-macro (struct-map type:struct-id instance-expr:expr 
map-function-expr:expr)
  (let ([map-function map-function-expr]
[instance instance-expr])
(type.constructor-id (map-function (type.accessor-id instance)) ...)))

(struct point (x y z) #:transparent)

;; Outputs (point 2 3 4)
(struct-map point (point 1 2 3) add1)
On Sunday, January 31, 2021 at 4:20:03 PM UTC-8 making-a-racket wrote:

> Hello. I have a project where I am needing to represent vectors (in the 
> mathematical sense), points, and colors. Both the vectors and points will 
> be 3D. I'm having trouble knowing what's an idiomatic way to represent and 
> interact with data types that are similar but different.
>
> In general, I could simply all represent them with a list or vector (in 
> the Racket sense). So I could have:
>
> (define (vector i j k) #(i j k))
> (define (point x y z) #(x y z))
>
> Then I could readily use the existing vector functions, such as vector-map 
> without having to define my own. But I don't super like this because I have 
> to define my own accessor functions like vector-i and point-y and also 
> don't get predicates like vector? for free.
>
> Another way is that I could use structs, but then I'm stuck implementing 
> things myself and across the structs. To avoid the latter point, I could 
> use pattern matching. So something like:
>
> (struct vector (i j k))
> (struct point (x y z))
>
> (define (tuple-map proc tuple)
>   (match tuple
> [(struct vector (i j k)) (vector (proc (vector-i tuple))
>  (proc (vector-j tuple))
>  (proc (vector-k tuple)))]
> [(struct point (x y z)) (point (proc (point-x tuple))
>(proc (point-y tuple))
>(proc (point-z tuple)))]
> [(struct color (r g b)) (color (proc (color-r tuple))
>(proc (color-g tuple))
>(proc (color-b tuple)))]))
>
> But of course, this map doesn't take multiple tuples. And this feels 
> awkward, because I'll need to implement other things, like fold. Map and 
> fold would be used in defining new operators on vectors and points, like 
> addition, normalization (for vectors only), etc.
>
> The ideal thing would be that I could define a struct for these types, 
> that had the accessor functions like vector-i and predicates likes vector? 
> but was actually represented by a vector (in the Racket sense) underneath 
> the hood. Does something like this exist in Racket (not classes please).
>
> In F#, I did this same thing using F#'s records for the vector, point, and 
> color data types, and they inherited an ITuple interface (F#'s immutable, 
> functional data types can implement interfaces). Can Racket's stucts 
> inherit from interfaces? Is there something I can do with generics?
>
> Thanks for any help on this design.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/a0220f5d-e278-454a-bc57-b7686551e486n%40googlegroups.com.


[racket-users] Resyntax: an automated refactoring tool for Racket

2021-01-24 Thread jackh...@gmail.com
Hello everyone! Just wanted to announce a neat project I've been working 
on: Resyntax , a tool for 
refactoring racket code. Currently the tool is able to replace various uses 
of `let` forms with `define`, as can be seen in this pull request 
.

The tool works by hooking in to the racket macro expander and applying 
*refactoring 
rules* to the code as it's being expanded, where a refactoring rule is a 
syntax-parse macro that says how to rewrite some code pattern. You can see 
all of the refactoring rules I've implemented so far in the 
resyntax/refactoring-rule 
 
module.

Resyntax is in the early stages. It works well enough when run manually on 
single files, and it has some nice features already:

   - Output is correctly indented
   - Rules are hygienic, so Resyntax's rules for replacing `let` with 
   `define` won't run on code where `let` is bound to something other than the 
   `let` from `racket/base`.
   - If a rule leaves a subform untouched, the formatting of that form is 
   left completely unchanged by the tool.

But it's got some issues that need to be worked out:

   - No public API for running it.
   - No documentation on how to create your own refactoring rules.
   - Deletes comments sometimes.
   - Doesn't enforce that code produced by a refactoring rule actually 
   compiles.
   - Current rules are not all that robust yet and may sometimes produce 
   buggy or badly formatted code.
   
If you're interested in following along with Resyntax's development, see 
the github repository . If you've 
got some suggestions for rules, follow the guidance in this github issue 
 to tell me all about your 
ideas. And, as usual, I can be reached by email and in the racket Slack and 
Discord servers.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/93f92eb3-00ad-4b59-818a-7848e984f7ecn%40googlegroups.com.


Re: [racket-users] Historical note.

2020-11-09 Thread jackh...@gmail.com
I'm glad, I didn't expect my comment to be so helpful :)

For those curious, I have several examples of this pattern in Rebellion. 
The following constructs are all just structs of functions:

   - Comparators 
   - Converters 
   - Equivalence relations 
   
   - Reducers 
   - Transducers 

On Monday, November 9, 2020 at 2:03:52 AM UTC-8 unlimitedscolobb wrote:

> On Monday, November 9, 2020 at 1:51:05 AM UTC+1 Kieron Hardy wrote:
>
>>
>> > On Nov 8, 2020, at 2:58 PM, Hendrik Boom  
>> wrote: 
>> > 
>> >> On Sun, Nov 08, 2020 at 12:47:11PM -0800, unlimitedscolobb wrote: 
>> >> The idea of having structs whose fields contain functions has never 
>> occurred to me ... 
>> > 
>> > Historical note: 
>> > 
>> > I first encountered structures containing function in the source code 
>> for 
>> > OS/360 way back in the late 60's. In assembler. 
>> > 
>>
> Structures with fields containing functions has never occurred to me 
>> before, either, at least not in those terms. 
>>
>> However isn’t that exactly one of the key design principles behind how 
>> device-drivers are implemented and installed into an OS? And also how 
>> classes and objects were initially added to C as some pretty hairy #define 
>> macros and function pointers? 
>>
>> This design pattern insight would have been beneficial to me sooner - 
>> doh! 
>>
>>  
> I completely share your feelings Kieron.  In fact, I have already defined 
> structures with functions in the fields multiple times and in many 
> programming languages, but I have never thought how this pattern could be 
> used to implement generic-like functionality :D
>
> Thank you Hendrik for the historical note!
>
> -
> Sergiu
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/15dc0d41-dbd2-488a-9113-31c284443ce4n%40googlegroups.com.


[racket-users] Re: Generics vs. Classes?

2020-11-08 Thread jackh...@gmail.com
The typical use case for classes in Racket is writing GUIs, and that's 
mostly because the GUI framework is class based.

For most other use cases, generics are a better choice than classes. 
They're simpler and have a less intrusive effect on your API surface. If 
you don't need to support arbitrary user implementations, you can avoid 
generics and classes altogether and use structs whose fields contain 
functions.

On Sunday, November 8, 2020 at 6:12:37 AM UTC-8 unlimitedscolobb wrote:

> Hi,
>
> A general knowledge question: what would be the typical use cases of 
> Racket generics vs. the typical use cases of Racket classes?
>
> Am I correct in assuming that I can do everything with classes what I 
> could do with generics, and that generics have made their way into the 
> language before the classes?
>
> -
> Sergiu
>
> P.S. I'm reading the section on classes in the updated Typed Racket 
> reference, and I'm very happy to see this new functionality!  Very good job 
> the Typed Racket Team!
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/dc76fceb-9829-4356-a2fe-0d340fef9c43n%40googlegroups.com.


[racket-users] Re: Help implementing an early return macro

2020-11-04 Thread jackh...@gmail.com
A brief update on this: I went with Ryan's approach and used an 
implementation of guarded-block throughout Rebellion's codebase. You can 
see the diff here: https://github.com/jackfirth/rebellion/pull/466. A 
couple of things to note:

- I added a define/guard form that's like define, but with the function 
body implicitly wrapped with guarded-block.
- I tweaked the syntax of guard to allow either (guard  else 
 ...) or (guard  then  ...). If else is used, the 
guard is taken if the condition is false. If then is used, the guard is 
taken if the condition is true. This made it easier to organize my code 
such that the short-circuiting precondition checks came before what I 
considered to be the main branch of the function. With just the else case, 
sometimes I had to awkwardly negate things.

There's a few problems related to robustness I'd like to figure out 
eventually, before documenting this macro and publicly exposing it:

- It allows shadowing. If a variable is defined both before and after a 
guard statement, the definition after shadows the one before it, instead of 
raising a duplicate definition error.
- If any definitions raise syntax errors, the error is reported in terms of 
the expanded define-values form instead of the definition the user actually 
wrote.
- The last body form of a guarded block shouldn't be allowed to be a guard 
statement, and a good error message should be raised if a user does that. 
The current implementation doesn't check for that.

The last one is pretty easy to fix, but the other two I'm not sure how to 
fix.

On Sunday, November 1, 2020 at 1:04:15 PM UTC-8 gneuner2 wrote:

> On Sat, 31 Oct 2020 03:25:32 -0700 (PDT),
> "jackh...@gmail.com"
>  wrote:
>
> >Wow, these are a lot of great responses. First of all, *awesome* job 
> Ryan. 
> >That implementation is exactly what I needed to figure out. I'm 
> definitely 
> >starting there first.
> >
> >> Are you looking for `let/ec`?
> >
> >I'd forgotten about that one. That has the *syntax* I want. However my 
> >issue with continuation-based approaches isn't the syntax, or even the 
> >performance. It's the semantics. What if someone writes code like this?
> >
> >(guarded-block
> > (define x (random 10))
> > (thread
> > (lambda ()
> > (guard (even? x) else #false)
> > ...)))
> >
> >If I implemented guarded-block in terms of let/ec, then what does this 
> code 
> >even *do*? I honestly don't know. It would probably run without error and 
> >do... something. 
>
> (let/ec return
> (thread
> (lambda ()
> (return -1)
> 42)))
>
> throws an error: "continuation application: attempt to jump into an
> escape continuation"
>
> There is a continuation barrier between the threads.
>
>
> However, let/cc works: e.g.,
>
> (let/cc return
> (thread
> (lambda ()
> (return -1)
> 42)))
>
> returns -1.
>
>
> >I am extremely sure that regardless of what it did, it 
> >would be confusing and it wouldn't solve any problem I had. 
>
> I am sure it would solve *some* problems.
>
>
> >I just flat out don't want to allow this or any related nonsense, 
> >such as:
> >
> >; Aliasing
> >(define return guard)
> >
> >; Higher-order usage
> >(map guard (some-list ...))
> >
> >; Capturing via closure
> >(guarded-block
> > (define (check-foo x) (guard (foo? x) else #false))
> > (check-foo ...)
> > ...)
> >
> >; Capturing via mutation
> >(set! previous-guard guard)
> >
> >; Oh great, now I have to think about even more continuation jumps
> >(dynamic-wind
> > (lambda () (guard ...))
> > (lambda () ...)
> > (lambda () ...))
> >
> >There might be valid use cases for some of these, but I certainly don't 
> >understand those use cases well enough to commit to a semantics for them.
>
> It always is safe to jump upwards OUT of a lower level computation.
> The sticky issues [and mental gyrations] with continuations all have
> to do with jumping downwards or sideways.
>
> I'm not sure what problems you might have with continuation barriers:
> the example of the thread shows that (upward-only) "escape"
> continuations don't work across threads ... but "full" continations do
> work, and would still work even if the threads were siblings rather
> than in a parent/child relationship.
>
> The issue for your purpose would be making sure the continuation is
> called from a position that is guaranteed to terminate the errant
> thread: you might need to recognize a thread as a special case, wrap
> it and (like an exception) catch/rethrow the continuation.
>
>
> Or, if you don't care about sibling threads, just use exceptions which
> always can be thrown upward out of child threads.
>
> George
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/d7714f66-d791-4ec8-a1c1-da8a9c761caen%40googlegroups.com.


[racket-users] Re: large hash/dc errors (was: Contracts for (partially) specifying dictionary key -> value-predicates)

2020-10-31 Thread jackh...@gmail.com
I have the same issue for ->i contracts. I'll write multiple #:pre/desc 
checks with nice messages, which are promptly rendered useless by the fact 
that ->i prints out the whole contract instead of just the precondition 
check that failed.
On Friday, October 30, 2020 at 7:16:59 PM UTC-7 Ben Greenman wrote:

> > Ben: if you have an example of the bad hash/dc error message I'd be
> > interested to see it.
> >
> > Robby
>
> Here's the kind of message that turned me off:
>
> ```
> ctc.rkt:34:0: broke its own contract
> promised: (hash/dc (k (or/c (quote a) (quote b) (quote c))) (v (k)
> (config-value/c k)) #:immutable #t #:kind (quote flat))
> produced: '#hash((a . 1) (b . #t) (c . #))
> in: (hash/dc
> (k (or/c 'a 'b 'c))
> (v (k) (config-value/c k))
> #:immutable
> #t
> #:kind
> 'flat)
> contract from: +
> blaming: +
> (assuming the contract is correct)
> ```
>
> It prints the whole hash and contract, leaving me to figure out the
> two key parts: (1) what piece of the hash failed, and (2) what the
> contract expected for that piece.
>
> Now that I think of it ->* is bad in the same way --- especially for
> `plot` functions.
>
>
> Here's the code that made that error message. The #;(lambda )
> comment is the contract that I ended up using instead of hash/dc (it
> still doesn't explain bad values well).
>
> ```
> #lang racket/base
>
> (require racket/contract)
>
> (provide config/c)
>
> (define config-key/c
> (or/c 'a 'b 'c))
>
> (define (config-value/c k)
> (case k
> ((a)
> string?)
> ((b)
> boolean?)
> ((c)
> void?)))
>
> (define config/c
> #;(lambda (h)
> (for ((k (in-list (list 'a 'b 'c
> (unless (hash-has-key? h k)
> (raise-arguments-error 'config/c "missing key" "key" k "hash" h))
> (define v (hash-ref h k))
> (unless ((config-value/c k) v)
> (raise-arguments-error 'config/c "bad value for key" "key" k
> "value" v "hash" h))
> (void)))
> (hash/dc
> [k config-key/c]
> [v (k) (config-value/c k)]
> #:immutable #true
> #:kind 'flat))
>
> (contract
> config/c
> (hash 'a 1 'b #true 'c (void))
> '+
> '-)
> ```
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/3b0ed32b-4875-4cfa-9b2b-e4398e4318d1n%40googlegroups.com.


Re: [racket-users] Contracts for (partially) specifying dictionary key -> value-predicates

2020-10-31 Thread jackh...@gmail.com
I'm not sure, but I have a feeling Ben's suggestion to make them functions 
instead of macros wasn't about the performance implications of macros. I 
think it was about this particular symmetry:

- A (list 1 'apple "banana") is a (list/c number? symbol? string?)
- A (hash 'a 1 'b "foo") is a (dictof 'a number? 'b string?)

That is, when the keys are known statically, all the functions for creating 
dictionaries and hashes typically go with a flat and alternating sequence 
of key-value arguments. I think a contract combinator for dicts where the 
keys are known should have the same shape.

One other point: dictof is a confusing name. We would have list/c and 
listof, vector/c and vectorof, and hash/c and dictof. And the first two 
pairs would make the exact opposite decision as the third pair about which 
name is for the heterogeneous known-size case and which is for homogeneous 
collections.

Honestly I'd suggest naming it heterogeneous-dict/c. The contract will 
almost always span multiple lines no matter how long a name you pick, and 
I'm sick and tired of guessing which one of list/c, listof, *list/c, and 
list*of is the one I actually want. Words are underrated.
On Friday, October 30, 2020 at 12:43:02 PM UTC-7 William J. Bowman wrote:

> Thanks for the feedback! Some of these were not concerns for my use case, 
> so I’ll do a bit more design before submitting something.
>
> -- 
> Sent from my phoneamajig
>
> > On Oct 30, 2020, at 12:36, George Neuner  wrote:
> > 
> > 
> >> On 10/30/2020 3:08 PM, William J. Bowman wrote:
> >> Let me aid this discussion by copying in the ~10 lintes of code in 
> question:
> >> 
> >> > (define-syntax (dictof syn)
> >> > (syntax-parse syn
> >> > [(_ (k:id pred?) ...)
> >> > (quasisyntax/loc syn
> >> > (dictof/proc `((k . ,pred?) ...)))]))
> >> > > (define ((dictof/proc spec) h)
> >> > (and (eq? (dict-keys h) (dict-keys spec))
> >> > (for/and ([(k pred?) (in-dict spec)])
> >> > (pred? (dict-ref h k)
> >> 
> >> The macro is merely a syntactic transformation to 1 line of code that 
> implements
> >> the functionality of the contract at run-time.
> >> Is there some reason to avoid macros in this particular case?
> > 
> > There's rarely any problem with macros that only provide syntactic sugar.
> > 
> > The issues wrt contracts are how heavy are the dictionary functions. The 
> FOR loop is concerning because the check time is proportional to the size 
> of the dictionary [again recalling that contracts live on in release code].
> > 
> > For performance it would be better to enforce the predicate on values as 
> they are entered, and then assume anything already in the dictionary is 
> correct. It is sensible to provide a function that validates the whole 
> dictionary, but I would make it something the programmer has to invoke 
> deliberately rather than a contract to be enforced at (even just 1st in 
> module) mention of the dictionary.
> > 
> > YMMV,
> > George
> > 
> > -- 
> > You received this message because you are subscribed to the Google 
> Groups "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send 
> an email to racket-users...@googlegroups.com.
> > To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/95997336-33d4-5c5b-b329-9ea691fe59ef%40comcast.net
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/3de9c8ac-fa4f-44c3-8ce1-dcf041ecb8c1n%40googlegroups.com.


Re: [racket-users] Re: Help implementing an early return macro

2020-10-31 Thread jackh...@gmail.com
Wow, these are a lot of great responses. First of all, *awesome* job Ryan. 
That implementation is exactly what I needed to figure out. I'm definitely 
starting there first.

> Are you looking for `let/ec`?

I'd forgotten about that one. That has the *syntax* I want. However my 
issue with continuation-based approaches isn't the syntax, or even the 
performance. It's the semantics. What if someone writes code like this?

(guarded-block
  (define x (random 10))
  (thread
(lambda ()
  (guard (even? x) else #false)
  ...)))

If I implemented guarded-block in terms of let/ec, then what does this code 
even *do*? I honestly don't know. It would probably run without error and 
do... something. I am extremely sure that regardless of what it did, it 
would be confusing and it wouldn't solve any problem I had. I just flat out 
don't want to allow this or any related nonsense, such as:

; Aliasing
(define return guard)

; Higher-order usage
(map guard (some-list ...))

; Capturing via closure
(guarded-block
  (define (check-foo x) (guard (foo? x) else #false))
  (check-foo ...)
  ...)

; Capturing via mutation
(set! previous-guard guard)

; Oh great, now I have to think about even more continuation jumps
(dynamic-wind
  (lambda () (guard ...))
  (lambda () ...)
  (lambda () ...))

There might be valid use cases for some of these, but I certainly don't 
understand those use cases well enough to commit to a semantics for them.

As for why not use condd, cond/else, or parendown: because they don't look 
right. Specifically, I often write code like this:

(define (f x y z)
  ... a few lines of checking preconditions ...
  ... a dozen or two lines of actual useful logic ...)

I don't want to indent the useful logic a bunch. That's the most important 
part of the function - the preconditions are minor things that you should 
be able to skim over and forget about. If my functions without 
preconditions look wildly different from my functions with preconditions, 
it becomes difficult to tell what the main focus of a function is. Not to 
mention that going from zero preconditions to one (and from one to zero) 
now introduces a bunch of busywork.

On naming: I like the symmetry between return-when / return-unless and when 
/ unless, but the problem is the word "return". If I call it a return 
statement, people will naturally expect this to work:

(define (first-owl animals)
  (for ([animal animals])
(return-when (owl? animal) animal)))

I don't want to have to explain why that doesn't work forty times.

The names guard-when and guard-unless are kind of ambiguous; does 
"guard-when" mean "when this condition is true, enter this guard block and 
escape" or does it mean "guard the function with this condition, if it 
fails enter the block and escape". Does "guard" mean "prevent this 
condition" or "ensure this condition"? Having two forms means you have to 
remember which one means which and figure out a way to keep them straight. 
I'd rather just have one form so there's only one way to do it, and you can 
teach yourself that "ah yes, guard always means 'make sure this is true'".

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/3607a1a0-e303-4d9d-a62e-c958712aa2c8n%40googlegroups.com.


[racket-users] Re: hash-filter: PR or not PR

2020-10-31 Thread jackh...@gmail.com
This is definitely a useful thing to have and I've wanted it myself before. 
However I'm generally of the opinion that we should avoid making more 
collection manipulation functions that are unnecessarily specialized to one 
type of collection. I'd like to see functions that operate on all sequences 
rather than on hash tables alone. Here are some usages of hash-filter 
compared with some existing alternatives:

(hash-filter ht #:predicate pred)
==
; Sequence composition
(make-immutable-hash
 (sequence->list
  (sequence-filter (lambda (pair) (pred (cdr pair)))
   (sequence-map cons ht
==
; For macros
(for/hash ([(k v) (in-hash ht)] #:when (pred v)) (values k v))

The for macro is probably what I'd reach for in standard racket code. It 
has some drawbacks: the first time I tried to write it I forgot to write 
(values k v) and instead just wrote v. Keeping track of pulling apart the 
key and value, naming them with variables, and putting them back together 
is a little annoying.

The sequence composition approach is, in my humble opinion, completely 
unreadable and difficult to write to boot. The sequence-map function works 
totally fine on multivalued sequences but sequence-filter only works on 
single-value sequences, so we have to do a dance with cons car and cdr to 
turn the multivalued sequence of keys and values into a single-valued 
sequence of key-value cons pairs. Furthermore, the only built-in function 
for building a hash table from a sequence is overly specialized to lists, 
so you have to copy the sequence into a list solely so you can turn that 
list into a hash table with make-immutable-hash.

Instead of adding hash-filter to racket/hash, I think there's a few 
improvements we could make to the sequence composition side of things:

- Make sequence-filter allow multivalued sequences, provided the arity of 
the predicate is consistent with the arity of the sequence.
- Add a sequence->hash function that accepts a multivalued sequence of keys 
and values (exactly like what in-hash produces) and copies them into a hash 
table.

For the filter-by-value, filter-by-key, and filter-by-key-and-value cases, 
this lets us write:

(sequence->hash (sequence-filter (lambda (k v) (pred v)) ht)) ; Filter 
values
(sequence->hash (sequence-filter (lambda (k v) (pred k)) ht)) ; Filter keys
(sequence->hash (sequence-filter pred ht)) ; Filter key-value pairs

Which is close enough to hash-filter to satisfy my desire for conciseness, 
while still being general enough to work with other kinds of key-value 
sequences.

Shameless self plug: you might be interested in Rebellion 
's take on this, which 
uses transducers  and key-value structs called entries 
:

(transduce (in-hash-entries ht) (filtering-values pred) #:into into-hash) ; 
Filter values
(transduce (in-hash-entries ht) (filtering-keys pred) #:into into-hash) ; 
Filter keys
(transduce (in-hash-entries ht) (filtering (lambda (e) (pred (entry-key e) 
(entry-value e #:into into-hash) ; Filter key-value entries
On Friday, October 30, 2020 at 4:35:31 PM UTC-7 unlimitedscolobb wrote:

> Hi,
>
> I am currently using hash tables a lot, so inevitably I end up writing 
> general functions.  I wrote the following `hash-filter`:
>
> ```
> (define (hash-filter
>  ht
>  #:predicate [predicate #f]
>  #:predicate/key [predicate/key
>   (if predicate
>   (λ (_ v) (predicate v))
>   (error 'hash-filter))])
>   (for/fold ([filtered-pairs (hash-clear ht)])
> ([(k v) (in-hash ht)])
> (if (predicate/key k v)
> (hash-set filtered-pairs k v)
> filtered-pairs)))
> ```
>
> Before I submit a pull request to the Racket repository, I would like to 
> know whether adding this function to `racket/hash` is a good idea, or 
> whether I should create a separate package with extra functions for hash 
> tables.
>
> -
> Sergiu
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/98498f48-9d02-4f4e-91fd-ab85bf6d765an%40googlegroups.com.


Re: [racket-users] Re: Memory usage of (port->lines ...) is extreamly high

2020-09-29 Thread jackh...@gmail.com
I'm also guessing the jump from 600MB to 3GB is related to encodings. The 
file is probably UTF8/ASCII, and racket strings are a different encoding. I 
think they're one of the 32-bit encodings? So for ASCII text that alone 
would be a factor of four increase in memory usage.

On Thursday, September 24, 2020 at 5:55:48 AM UTC-7 Sam Tobin-Hochstadt 
wrote:

> port->lines produces a list with all the lines in it. That list is what 
> uses all the memory. Using in-lines avoids producing the whole list at 
> once. 
>
> Sam
>
> On Thu, Sep 24, 2020, 8:53 AM Hong Yang  wrote:
>
>> Thanks Laurent, I tried (in-lines...), and yes, it's memory-efficient, 
>> but I still curious and concern why (port->lines ...) takes so many memory.
>>
>> Best regards
>> Hong
>>
>> On Thursday, September 24, 2020 at 6:55:10 PM UTC+8 laurent...@gmail.com 
>> wrote:
>>
>>> Quick comment: of you don't need to load the whole file but want to 
>>> parse it line by line, use `in-lines` which is memory-efficient.
>>>
>>> On Thu, Sep 24, 2020, 11:46 Hong Yang  wrote:
>>>
 Update with memory dump log attached.

 1. With out (set! input empty), call (collect-garbage) doesn't help
 2. Call (set! input empty) and (collect-garbage), memory reduce 
 dramaticly.

 ; 214M(VIRT)/101M(RSS) without open any file
 (let loop()
   (sleep 5)  ; Waiting here so that I can check it via top/ps
   (dump-memory-stats)
   (collect-garbage)
   (set! input empty)  ; Even not help with this line, it works after 
 called (collect-garbage) explicity.
   (loop))

 On Thursday, September 24, 2020 at 6:14:55 PM UTC+8 Hong Yang wrote:

> Hi Racketer
>
> I'm trying to load a log file which size is 600MB, then I found the 
> program exhausted 3 GB resident memory just for load all the content of 
> it 
> via (port->lines...). I do have enough RAM but it looks like some thing 
> went wrong here, and I do need to load them all into RAM for my use case 
> so 
> (read-line ...) doesn't help me.
>
> Any comment would be preciated.
>
> Here is may programe:
>
> #!/usr/bin/racket
> #lang racket
>
> ; Load input as list of lines
> (define (input-load-lines file-name)
>   (if (file-exists? file-name)
>   (let* ([input (open-input-file file-name)]
>  [lines (port->lines input)])
> (close-input-port input)
> lines)
>   empty))
>
> ; Racket 7.8, compile from source code, (none cs mode)
> ; 100M of log requires 0.5G runtime memory
> ; 300M of log requires 1.5G runtime memory
> ; 600M of log requires 3.0G runtime memory
> ;
> ; Reference
> ;   racket/collects/racket/port.rkt :106
> ;   racket/collects/racket/private/portlines.rkt :11
>
> (define input (input-load-lines "main.log"))
>
> ; 214M(VIRT)/101M(RSS) without open any file
> (let loop()
>   (sleep 5) ; Waiting here so that I can check it via top/ps
>   (set! input empty) ; event not help with this line
>   (loop))
>
> Thanks
> Hong
>
 -- 
 You received this message because you are subscribed to the Google 
 Groups "Racket Users" group.
 To unsubscribe from this group and stop receiving emails from it, send 
 an email to racket-users...@googlegroups.com.
 To view this discussion on the web visit 
 https://groups.google.com/d/msgid/racket-users/07c41b96-87ba-473a-ad0e-0cec71dc4024n%40googlegroups.com
  
 
 .

>>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Racket Users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to racket-users...@googlegroups.com.
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/racket-users/f761c588-da7e-43d4-9b05-b917f64f4b52n%40googlegroups.com
>>  
>> 
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/4b11510f-fb14-496b-b7be-b52abfa37982n%40googlegroups.com.


Re: [racket-users] Why is get-impure-port* slower than a system call to curl?

2020-09-15 Thread jackh...@gmail.com
Curl supports http/2 (and even has experimental support for http/3 which is 
orders of magnitude faster than http/1.1. Depending on what protocols the 
server you're talking to supports, that could be part of it.

On Monday, September 14, 2020 at 3:42:37 PM UTC-7 samdph...@gmail.com wrote:

> Hi Stephen,
>
> I ran this small benchmark against a remote web server, and was
> definitely getting better response using the http-easy module.
>
> https://gist.github.com/samdphillips/32763ebd0d938678c2972b1dd8ee5778
>
> $ racket -e '(require (submod "http-perf.rkt" curl))'
> cpu time: 768 real time: 35299 gc time: 0
>
> $ racket -e '(require (submod "http-perf.rkt" http-easy))'
> cpu time: 1810 real time: 17316 gc time: 70
>
> On Mon, Sep 14, 2020 at 12:57 PM Stephen Foster  
> wrote:
> >
> > Finally circling back to this issue. I've disabled debugging in DrRacket 
> and also done a test outside of DrRacket. It's still slow. :(
> >
> > I also tried the newer HTTP client: 
> https://docs.racket-lang.org/http-easy/index.html. Like the others, it is 
> also slow.
> >
> > I'll do some more digging. I'm currently trying to figure out if this is 
> a "just me" / "just my system" problem. So... I'd be grateful if anyone who 
> has written code that sends HTTP requests from Racket could chime in with: 
> 1) I can confirm that sending HTTP requests from Racket has always been 
> fast for me, or 2) I too have noticed Racket HTTP requests are slow.
> >
> > (Note that by "slow", I mean: takes noticeably longer than curl.)
> >
> >
> >
> > On Tue, Jul 7, 2020 at 12:21 PM Jon Zeppieri  wrote:
> >>
> >> Hi Stephen,
> >>
> >> Your video shows you running this code in DrRacket with debugging
> >> enabled. That usually affects performance. Have you made measurements
> >> when running this code outside of DrRacket?
> >>
> >> - Jon
> >>
> >>
> >> On Tue, Jul 7, 2020 at 2:13 PM Stephen Foster  
> wrote:
> >> >
> >> > I'm considering using Racket to remake my 3D game CodeSpells. I'm 
> using http requests to have Unreal Engine and Racket talk to each other.
> >> >
> >> > When I use the http/request library, Racket fires off its GET request 
> much slower than if it were to do a system call to curl. (Same is true if I 
> use simple-http, which makes me think the problem might be a deep one.)
> >> >
> >> > Here's a video to demo the issue. Notice how, with curl, the 
> experience is playable, whereas with the Racket function, there's way too 
> much time between the spell landing and the effect occurring:
> >> >
> >> > https://youtu.be/jTqUFVlfBFA
> >> >
> >> > Obviously, I'd like to do things in a Rackety way. But I'm not above 
> doing things the silly way. I'd just be grumpy about it.
> >> >
> >> > Any ideas?
> >> >
> >> >
> >> >
> >> > --
> >> > You received this message because you are subscribed to the Google 
> Groups "Racket Users" group.
> >> > To unsubscribe from this group and stop receiving emails from it, 
> send an email to racket-users...@googlegroups.com.
> >> > To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/997693d6-b94a-4f69-85cf-aa475c807b20n%40googlegroups.com
> .
> >
> >
> >
> > --
> >
> >
> > Stephen Foster
> > ThoughtSTEM Co-Founder
> > 318-792-2035 <(318)%20792-2035>
> >
> > --
> > You received this message because you are subscribed to the Google 
> Groups "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send 
> an email to racket-users...@googlegroups.com.
> > To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/CA%2BzSu2_%2BTKVTe--OZRU_BE_LyofFkA869c-2v%2BRJ76HjDQt4_w%40mail.gmail.com
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/1c8664fa-e8f2-49c8-8417-101dd7186231n%40googlegroups.com.


Re: [racket-users] package manager woes on Windows 10?

2020-09-12 Thread jackh...@gmail.com
Could we make the "do what I mean" box just automatically strip any 
newlines pasted into it? It seems sensible to me to require that it only be 
a single line input.

On Friday, September 11, 2020 at 6:22:59 AM UTC-7 hen...@topoi.pooq.com 
wrote:

> On Thu, Sep 10, 2020 at 10:27:39AM -0400, George Neuner wrote:
> > 
> > 
> > On 9/10/2020 10:06 AM, Philip McGrath wrote:
> > > Also, this is happening over encrypted HTTPS: no one is sniffing the
> > > User-Agent header.
> > 
> > While it may not be the issue here, you need to understand that appliance
> > firewalls CAN and routinely DO examine data inside encrypted connections.
>
> Using man-in-the-middle attacks?
>
> -- hendrik
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/84b16cf0-7837-4d54-9423-c1286f5e2b7an%40googlegroups.com.


[racket-users] Re: hashcons

2020-09-12 Thread jackh...@gmail.com
Not automatically, but you can make your own wrapper function around cons 
that interns them using a weak hash table and then you can use that wrapper 
function everywhere.

On Thursday, September 10, 2020 at 7:34:37 PM UTC-7 hen...@topoi.pooq.com 
wrote:

> Is there a way to run Racket so that every immuable cons is made with 
> a hashcons operation; i.e. it makes a new cons scel only if there 
> isn't already one in memory somewhere with the same car and cdr 
> values?
>
> -- hendrik
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/7ed721c9-4ed2-47eb-b8bb-a30a1ed9125fn%40googlegroups.com.


[racket-users] Re: Pretty Printing for ASTs represented as structs

2020-08-16 Thread jackh...@gmail.com
I recommend using make-constructor-style-printer 
,
 
which automates a lot of the fiddly indentation-handling you'd have to do 
otherwise.
On Sunday, August 16, 2020 at 1:48:50 PM UTC-7 jerem...@gmail.com wrote:

>
> Hi All,
>
> I'm looking into using Racket structs to represent abstract syntax trees.
> I've gotten as far as defining gen:custom-write properties, but have not
> yet figured out how to control indenting. Also, I'm not sure I'm just 
> calling
> write-string, write, and newline in my gen:custom-write methods, which I
> suspect is not exactly correct.
>
> Are there some good up-to-date examples of this that I could look at?
>
> Thanks,
> Jeremy
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/f11193f4-9fb5-43fd-a54e-f5ebb5c9bb69n%40googlegroups.com.