
Hello, I’m trying to port two Haskell functions into typed Racket. They are, picks [] = []
picks (x:xs) = (x, xs):[(y, x:ys) \| (y, ys) <- picks xs]
pairs xs = [((x, y), zs) \| (x,ys) <- picks xs, (y, zs) <- picks ys]
My implementation is as follows, (: picks (All (a) (-> (Listof a) (Listof (Listof a)))))
(define (picks lst)
(cond
[(null? lst) '()]
[else (cons
lst
(map
(λ ([l : (Listof a)]) (cons (car l) (cons (car lst) (cdr l))))
(picks (cdr lst))))]))
(: pairs (All (a) (-> (Listof a) (Listof (Listof a)))))
(define (pairs lst)
(for*/list ([x/ys (picks lst)]
[y/zs (picks (cdr x/ys))])
(cons
(car x/ys)
y/zs)))
I think it should type check but I got an error, Type Checker: Error in macro expansion -- insufficient type information to typecheck. please add more type annotations in: (for*/list ((x/ys (picks lst)) (y/zs (picks (cdr x/ys)))) (cons (car x/ys) y/zs))
I tried to added type annotations but always got syntax errors. Could you give me some pointers? Thanks.

@shaobo (: pairs (All (a) (-> (Listof a) (Listof (Listof a)))))
(define (pairs lst)
(for*/list : (Listof (Listof a))
([x/ys (picks lst)]
[y/zs (picks (cdr x/ys))])
(cons
(car x/ys)
y/zs)))

@robby Is it possible something changed with the SSL config at northwestern to cause this? http://drdr.racket-lang.org/60358/cs/racket/share/pkgs/redex-test/redex/tests/ryr-test.rkt

Yes.

I’ve asked IT to look into it (earlier this morning). Haven’t heard back yet.

Ok great, thanks!

Is the struct
form written in Racket? I’d like to see how it defines the struct name and the transformer binding simultaneously (alternate question: how would I do that?)

I believe the Racket part is in define-struct.rkt
, struct.rkt
and struct-info.rkt
. https://github.com/racket/racket/blob/master/racket/collects/racket/struct.rkt


Ok, that seems to answer my question, thanks!

Is it fair to say this code is pretty far from idiomatic Racket? Or maybe weaving syntax at this level is pretty advanced…

That’s pretty far from idiomatic, because it’s pretty low level, and it’s pretty advanced.

It’s not idiomatic, but since structures are a part of “core” Racket, it’s important to keep the dependencies to a minimimum.

And it puts a lot of effort into error checking, and has to do it all manually because it doesn’t have access to tools like syntax-parse

Here’s a simple demonstration of the same thing: #lang racket
(require (for-syntax syntax/parse racket/syntax))
(define-syntax (mystruct stx)
(syntax-parse stx
[(_ name:id (fields:id ...))
#:with ((acc n) ...)
(for/list ([f (syntax-e #'(fields ...))]
[i (in-naturals)])
(list (format-id #'name "~a-~a" #'name f)
i))
#:with mk (format-id #'name "make-~a" #'name)
#'(begin (define mk list)
(define acc (λ (v) (list-ref v 'n))) ...)]))
(mystruct point (x y))
(point-x (make-point 1 2))

Ah, yes, that part I get — I was looking for how it binds the struct name to both the constructor and the transformer binding. So, my particular case would be to write the struct-out
provider syntax equivalent from your simple example @samth . It would need to use syntax-local-value
and examine the field names of a particular struct at syntax time AFAICT.

Ah, ok


here’s my initial attempt… I don’t know how to extract the field names to add to the list of make-export

struct-out
does this by grabbing the struct-info
from the transformer binding, which seems relatively straightforward (in this case it wouldn’t be a struct-info
, just a list probably)

I think this should give you the right idea: #lang racket
(require (for-syntax syntax/parse racket/syntax))
(begin-for-syntax
(struct names (mk flds)
#:property prop:rename-transformer 0))
(define-syntax (mystruct stx)
(syntax-parse stx
[(_ name:id (fields:id ...))
#:with ((acc n) ...)
(for/list ([f (syntax-e #'(fields ...))]
[i (in-naturals)])
(list (format-id #'name "~a-~a" #'name f)
i))
#:with mk (format-id #'name "make-~a" #'name)
#'(begin (define mk list)
(define acc (λ (v) (list-ref v 'n))) ...
(define-syntax name (names #'mk (list #'acc ...))))]))
(mystruct point (x y))
(point-x (make-point 1 2))

That makes sense — I was getting hung up on the same name referring to both the constructor and the transformer, but even in my case that’s not necessary… I can use different names.

they have to have different names, but you don’t have to expose both names

what is the prop:rename-transformer
property for in the names struct?

if you just replace #:with mk (format-id ...)
with #:with mk (generate-temporary)
then it’s just a fresh name that no one will see

That lets you use name
as the constructor in an expression

ah :bulb:

clever

a great way to hide the transformer value in plain sight

Although if I try to grab the value of the syntax binding it doesn’t work:

(define-syntax (get-mystruct-name stx)
(syntax-parse stx
([_ n:id]
#`'#,(syntax-local-value #'n)
)))
(get-mystruct-name point)

Applications/Racket v8.1/collects/syntax/wrap-modbeg.rkt:46:4: syntax-local-value: identifier is not bound to syntax: #<syntax:file.rkt:47:19 point>

Try (define-syntax (get-mystruct-name stx)
(syntax-parse stx
([_ n:id]
#`'#,(let-values ([(a b) (syntax-local-value/immediate #'n)])
a)
)))

syntax-local-value
is following the rename transformer

there are a few ways to fix that but that’s the easiest for now

that did it, thanks!

and the same call works on struct
definitions as well..