<div dir="ltr"><div class="markdown-here-wrapper" style><p style="margin:1.2em 0px!important">That was my general approach, however I had to do a bit more analysis. That macro expands  <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248)">(:/c f (A B) (-> B (-> A B))</code> to <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248)">(: f (All (A) (-> B (All (B) (-> A B)))))</code>. I’ve come up with something that checks the argument types in a basic function contract and only provides the polymorphic variables that are used, then wraps the returned function type with any unused type variables. It's combined with some useful syntax for complex function types. The source is available at <a href="https://github.com/jackfirth/compact-annotations">https://github.com/jackfirth/compact-annotations</a> and it’s available as a package in the catalog. Let’s you write polymorphic types much more neatly:</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre;overflow:auto;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important">(:: map-list-to-vector A B => (Listof A) -> (A -> B) -> (Vectorof B))
(define ((map-list-to-vector lst) f)
  (list->vector (map f lst)))
</code></pre><p style="margin:1.2em 0px!important">If anyone’s interested in this, or if there’s any other shortcuts for type annotations people are interested in, I’d love some feedback.</p>
<div title="MDH:VGhhdCB3YXMgbXkgZ2VuZXJhbCBhcHByb2FjaCwgaG93ZXZlciBJIGhhZCB0byBkbyBhIGJpdCBt
b3JlIGFuYWx5c2lzLiBUaGF0IG1hY3JvIGV4cGFuZHMgwqBgKDovYyBmIChBIEIpICgtJmd0OyBC
ICgtJmd0OyBBIEIpKWAgdG8gYCg6IGYgKEFsbCAoQSkgKC0mZ3Q7IEIgKEFsbCAoQikgKC0mZ3Q7
IEEgQikpKSkpYC4gSSd2ZSBjb21lIHVwIHdpdGggc29tZXRoaW5nIHRoYXQgY2hlY2tzIHRoZSBh
cmd1bWVudCB0eXBlcyBpbiBhIGJhc2ljIGZ1bmN0aW9uIGNvbnRyYWN0IGFuZCBvbmx5IHByb3Zp
ZGVzIHRoZSBwb2x5bW9ycGhpYyB2YXJpYWJsZXMgdGhhdCBhcmUgdXNlZCwgdGhlbiB3cmFwcyB0
aGUgcmV0dXJuZWQgZnVuY3Rpb24gdHlwZSB3aXRoIGFueSB1bnVzZWQgdHlwZSB2YXJpYWJsZXMu
IEkndmUgY29tYmluZWQgaXQgd2l0aCBzb21lIHVzZWZ1bCBzeW50YXggZm9yIGNvbXBsZXggZnVu
Y3Rpb24gdHlwZXMuIFRoZSBzb3VyY2UgaXMgYXZhaWxhYmxlIGF0wqBodHRwczovL2dpdGh1Yi5j
b20vamFja2ZpcnRoL2NvbXBhY3QtYW5ub3RhdGlvbnMgYW5kIGl0J3MgYXZhaWxhYmxlIGFzIGEg
cGFja2FnZSBpbiB0aGUgY2F0YWxvZy4gTGV0J3MgeW91IHdyaXRlIHBvbHltb3JwaGljIHR5cGVz
IG11Y2ggbW9yZSBuZWF0bHk6PGRpdj48YnI+PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICg6OiBt
YXAtbGlzdC10by12ZWN0b3IgQSBCID0mZ3Q7IChMaXN0b2YgQSkgLSZndDsgKEEgLSZndDsgQikg
LSZndDsgKFZlY3Rvcm9mIEIpKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAoZGVmaW5lICgobWFw
LWxpc3QtdG8tdmVjdG9yIGxzdCkgZik8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7IChs
aXN0LSZndDt2ZWN0b3IgKG1hcCBmIGxzdCkpKTwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SWYg
YW55b25lJ3MgaW50ZXJlc3RlZCBpbiB0aGlzLCBvciBpZiB0aGVyZSdzIGFueSBvdGhlciBzaG9y
dGN1dHMgZm9yIHR5cGUgYW5ub3RhdGlvbnMgcGVvcGxlIGFyZSBpbnRlcmVzdGVkIGluLCBJJ2Qg
bG92ZSBzb21lIGZlZWRiYWNrLjwvZGl2Pg==" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0">​</div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 12, 2014 at 7:20 PM, Matthias Felleisen <span dir="ltr"><<a href="mailto:matthias@ccs.neu.edu" target="_blank">matthias@ccs.neu.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
Sorry that was a superfluous (premature) require:<br>
<br>
#lang typed/racket<br>
<span class=""><br>
;; syntax<br>
;; (:/c  f (α β γ) (-> A B (-> C (-> D E))))<br>
;; ==><br>
;; (: f (All (α) (-> A B (All (β) (-> C (All (γ) (-> D E)))))))<br>
(define-syntax (:/c stx)<br>
  (syntax-case stx (All/c)<br>
    [(_ f (A ...) τ) (let ([σ (All/c #'(A ...) #'τ)]) #`(: f #,σ))]))<br>
<br>
;; [List-of Syntax/id] Syntax -> Syntax<br>
;; distributes type variables along the right-most spine of a curried -> type<br>
;; given:<br>
;;  (α β γ) (-> A B (-> C (-> D E)))<br>
;; wanted:<br>
;; (All (α) (-> A B (All (β) (-> C (All (γ) (-> D E))))))<br>
(define-for-syntax (All/c α* C)<br>
  (syntax-case α* ()<br>
    [() C]<br>
    [(α) #`(All (α) #,C)]<br>
    [(α β ...)<br>
     (syntax-case C ()<br>
</span>       [(-> A ... B) #`(All (α) (-> A ... #,(All/c #'(β ...) #'B)))]<br>
<span class="im HOEnZb">       [(_ (α ...) A) #'(All (α ...) A)])]))<br>
<br>
;; -----------------------------------------------------------------------------<br>
<br>
(:/c compare-projection (A B) (-> (-> A A Boolean) (-> (-> B A) (-> B B Boolean))))<br>
(define (((compare-projection a<) b->a) b1 b2)<br>
  (a< (b->a b1) (b->a b2)))<br>
<br>
(define symbol<?<br>
  ((compare-projection bytes<?) (compose string->bytes/utf-8 symbol->string)))<br>
<br>
(symbol<? 'a 'b)<br>
<br>
<br>
<br>
</span><div class="HOEnZb"><div class="h5">On Nov 12, 2014, at 9:58 PM, Matthias Felleisen wrote:<br>
<br>
><br>
> You cannot write macros that expand within types (yet).<br>
><br>
> But you can write macros for : like this:<br>
><br>
> #lang typed/racket<br>
><br>
> (require (for-template (only-in typed/racket All ->)))<br>
><br>
> ;; syntax<br>
> ;; (:/c  f (α β γ) (-> A B (-> C (-> D E))))<br>
> ;; ==><br>
> ;; (: f (All (α) (-> A B (All (β) (-> C (All (γ) (-> D E)))))))<br>
> (define-syntax (:/c stx)<br>
>  (syntax-case stx (All/c)<br>
>    [(_ f (A ...) τ) (let ([σ (All/c #'(A ...) #'τ)]) #`(: f #,σ))]))<br>
><br>
> ;; [List-of Syntax/id] Syntax -> Syntax<br>
> ;; distributes type variables along the right-most spine of a curried -> type<br>
> ;; given:<br>
> ;;  (α β γ) (-> A B (-> C (-> D E)))<br>
> ;; wanted:<br>
> ;; (All (α) (-> A B (All (β) (-> C (All (γ) (-> D E))))))<br>
> (define-for-syntax (All/c α* C)<br>
>  (syntax-case α* ()<br>
>    [() C]<br>
>    [(α) #`(All (α) #,C)]<br>
>    [(α β ...)<br>
>     (syntax-case C ()<br>
>       [(-> A ... B)<br>
>        (let ([rst (All/c #'(β ...) #'B)])<br>
>          #`(All (α) (-> A ... #,rst)))]<br>
>       [(_ (α ...) A) #'(All (α ...) A)])]))<br>
><br>
> ;; -----------------------------------------------------------------------------<br>
><br>
> (:/c compare-projection (A B) (-> (-> A A Boolean) (-> (-> B A) (-> B B Boolean))))<br>
> (define (((compare-projection a<) b->a) b1 b2)<br>
>  (a< (b->a b1) (b->a b2)))<br>
><br>
> (define symbol<?<br>
>  ((compare-projection bytes<?) (compose string->bytes/utf-8 symbol->string)))<br>
><br>
> (symbol<? 'a 'b)<br>
><br>
><br>
><br>
> On Nov 12, 2014, at 8:56 PM, Jack Firth wrote:<br>
><br>
>> I've been mucking around with Typed Racket some and was writing a polymorphic curried function when something I found counter-intuitive popped up. I had this function:<br>
>><br>
>>    (: compare-projection (All (A B) (-> (-> A A Boolean) (-> (-> B A) (-> B B Boolean)))))<br>
>>    (define (((compare-projection a<) b->a) b1 b2)<br>
>>      (a< (b->a b1) (b->a b2)))<br>
>><br>
>> The purpose of this function was to let me compare things by converting them to some other type with a known comparison function, so something like symbol<? (which is defined in terms of bytes<? according to the docs) could be implemented directly like this:<br>
>><br>
>>    (define symbol<? ((compare-projection bytes<?) (compose string->bytes/utf-8 symbol->string)))<br>
>><br>
>> The problem I was having was that the first initial argument, bytes<?, only specifies the first type variable A. The other type variable B can still be anything, as it depends on what function you use to map things to type A in the returned function. The All type therefore assumes Any type for B, making the returned type non-polymorphic.<br>
>><br>
>> I expected something like currying to occur in the polymorphic type, since the returned type is a function. I thought that if a polymorphic function 1) returns a function and 2) doesn't have enough information from it's arguments to determine all it's type variables, that it should then automatically return a polymorphic function. In other words, I thought this type would be equivalent to this automatically:<br>
>><br>
>>    (All (A) (-> (-> A A Boolean) (All (B) (-> (-> B A) (-> B B Boolean)))))<br>
>><br>
>> This is most certainly not the case, though I wonder - would it be terribly difficult to define some sort of polymorphic type constructor that *did* behave like this? I'm fiddling with some macros for syntactic sugar of type definitions and it would be a boon to not have to worry about this.<br>
>> ____________________<br>
>> Racket Users list:<br>
>> <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
><br>
><br>
> ____________________<br>
>  Racket Users list:<br>
>  <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
<br>
</div></div></blockquote></div><br></div>