shaobo
2022-4-20 08:03:48

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.


soegaard2
2022-4-20 08:11:33

@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)))


samth
2022-4-20 17:39:57

@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


robby
2022-4-20 17:40:22

Yes.


robby
2022-4-20 17:40:33

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


samth
2022-4-20 17:40:40

Ok great, thanks!


dan.ml.901
2022-4-20 17:45:43

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?)


soegaard2
2022-4-20 17:47:47

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



dan.ml.901
2022-4-20 17:51:19

Ok, that seems to answer my question, thanks!


dan.ml.901
2022-4-20 17:52:06

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


samth
2022-4-20 17:53:51

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


soegaard2
2022-4-20 17:54:07

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


samth
2022-4-20 17:54:21

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


samth
2022-4-20 17:54:32

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))


dan.ml.901
2022-4-20 17:58:17

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.


samth
2022-4-20 17:58:34

Ah, ok


dan.ml.901
2022-4-20 17:59:48

dan.ml.901
2022-4-20 18:00:05

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


dan.ml.901
2022-4-20 18:01:00

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)


samth
2022-4-20 18:03:08

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))


dan.ml.901
2022-4-20 18:04:29

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.


samth
2022-4-20 18:04:53

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


dan.ml.901
2022-4-20 18:05:19

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


samth
2022-4-20 18:05:53

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


samth
2022-4-20 18:06:10

That lets you use name as the constructor in an expression


dan.ml.901
2022-4-20 18:06:53

ah :bulb:


dan.ml.901
2022-4-20 18:07:03

clever


dan.ml.901
2022-4-20 18:07:32

a great way to hide the transformer value in plain sight


dan.ml.901
2022-4-20 18:27:18

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


dan.ml.901
2022-4-20 18:27:20

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


dan.ml.901
2022-4-20 18:27:47

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>


samth
2022-4-20 18:29:36

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


samth
2022-4-20 18:29:52

syntax-local-value is following the rename transformer


samth
2022-4-20 18:30:12

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


dan.ml.901
2022-4-20 18:30:33

that did it, thanks!


dan.ml.901
2022-4-20 18:31:01

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