wesley.bitomski
2018-11-13 16:09:12

@wesley.bitomski has joined the channel


leif
2018-11-13 19:42:07

I’ll just leave this gem of a program here for you to enjoy: https://gist.github.com/LeifAndersen/94488e6937fa09fb96cde8234bd539ba


leif
2018-11-13 19:42:08

leif
2018-11-13 19:42:24

(Also, it runs way faster in racket 6.2 than 7.1 :disappointed: )


pocmatos
2018-11-13 19:57:53

@leif I was curious, so I tried it. I have to say, I didn’t ge tit. What’s special about it? Also, it goes pretty fast… when you say it runs faster in 6.2, are we talking ms here?


leif
2018-11-13 20:00:24

@pocmatos Yes, we are talking ms here. As for what to get…


leif
2018-11-13 20:01:13

Well, the oddity thing here is how (foo) expands differently in a module context and an expression context (and also an internal definition context, but that’s another story…)


leif
2018-11-13 20:01:55

In a module context, the expander sees (foo), sees that its not bound yet, assumes that its a definition that will get bound later, and expands to (#%app foo).


leif
2018-11-13 20:02:38

However, foo turns out to be a macro, so in the second pass, it gets further expanded to: (#%app (lambda () (writeln 42))), which writes 42 out to the console.


leif
2018-11-13 20:03:28

Note that this is different from what would happen if the definition of foo happened before its use, in that case the macro would expand to (lambda () (writeln 42)), which wouldn’t write 42 out to the console until its applied.


leif
2018-11-13 20:03:42

This is what happens to (writeln (foo)).


leif
2018-11-13 20:03:59

And why it doesn’t write 42 out to the console.


leif
2018-11-13 20:04:03

Does that make sense?


pocmatos
2018-11-13 20:06:59

Ah, yes, that makes sense.


pocmatos
2018-11-13 20:07:34

Odd indeed. It does write 42 to the console at least.: 42 #<procedure:...tos/tmp/leif.rkt:6:7>


pocmatos
2018-11-13 20:08:22

What’s odd is that I don’t see 42 42


pocmatos
2018-11-13 20:08:27

which is what I would expect.


michaelmmacleod
2018-11-13 20:09:09

If you change the writeln line to (writeln ((foo))) that’s what you would get


lexi.lambda
2018-11-13 20:23:13

I would argue that this behavior is questionably correct. While some of the behavior is unavoidable—the expander can’t know how foo will (or will not) be defined later—it essentially assumes that foo is a variable binding and treats it as a function application. The expander sometimes does similar things in other contexts, such as at the top level, or at phase > 0, but when it does so, it introduces an extra check: it records the assumption that foo will be a variable, not syntax, and it raises an error if foo is eventually bound as syntax. You can see this behavior in this program: #lang racket (begin-for-syntax (define (f) not-bound-yet)) (begin-for-syntax (define-syntax-rule (not-bound-yet) #f)) not-bound-yet.rkt:3:14: not-bound-yet: identifier treated as a variable, but later defined as syntax at phase: 1; the transformer environment in: not-bound-yet location...: not-bound-yet.rkt:3:14 I think there’s an argument to be made that the expander ought to do something similar when it assumes an unbound identifier will be an application and introduces #%app anyway.


leif
2018-11-13 20:30:42

@lexi.lambda Of course its consistent with the existing rules of the racket macro expander. That still doesn’t change the fact that its not really unexpected behavior.


lexi.lambda
2018-11-13 20:31:06

I think you misread me: my argument was that it was not consistent with the existing rules of the macroexpander.


leif
2018-11-13 20:31:42

Ah, okay.


lexi.lambda
2018-11-13 20:31:56

I think the macroexpander should reject that program!


leif
2018-11-13 20:32:05

Yes, okay, good.


leif
2018-11-13 20:32:08

I do too.


lexi.lambda
2018-11-13 20:33:02

The error message I mentioned demonstrates that the expander already has mechanisms in place to record the assumptions that it makes about unbound identifiers and signal an error if those assumptions turn out to be false.


lexi.lambda
2018-11-13 20:36:16

Though, admittedly, I’m not sure in practice if the change I’m suggesting is really a good one, for two reasons. First, if foo turns out to be bound as syntax to a result of make-variable-like-transformer or similar, then the current approach the macroexpander takes will go right. The change I’ve proposed would reject the program, anyway, which would negatively impact Turnstile-like techniques. Second, your program would have been rejected anyway if foo was defined as something other than an identifier macro, and identifier macros are relatively rare in practice in Racket (except via helpers that automatically create them, like make-rename-transformer and make-variable-like-transformer). On the other hand, the error message would still be confusing.


lexi.lambda
2018-11-13 20:36:56

In some sense, this might be a sign that a one-size-fits-all expander is hopeless, as I’m increasingly suspecting. :)


leif
2018-11-13 20:42:36

On, trust me, you’re not alone…sadly. :disappointed:


pocmatos
2018-11-13 20:54:20

Trying to make sense why Typed Racket complains: #lang typed/racket (define sha1sum (find-executable-path "sha1sum")) (unless sha1sum (error "no exe")) (define-values (proc out in err) (subprocess #f #f #f sha1sum)) I am pretty sure this is a common thing and I just don’t know the way out of it…


pocmatos
2018-11-13 20:54:53

but the checker still thinks that sha1sum might be #false by the time it gets to the subprocess call.


lexi.lambda
2018-11-13 20:59:06

I have no idea why the typechecker rejects that. @samth probably knows.


pnwamk
2018-11-13 21:00:32

sha1sum is a top level varialbe, top level variables are inherently mutable, mutable variables’ types are not updated by type tests


lexi.lambda
2018-11-13 21:00:55

This still fails, though: #lang typed/racket (let () (define sha1sum (find-executable-path "sha1sum")) (unless sha1sum (error "no exe")) (define-values (proc out in err) (subprocess #f #f #f sha1sum)) (void))


pocmatos
2018-11-13 21:01:02

@pnwamk same thing inside function


pocmatos
2018-11-13 21:01:26

@lexi.lambda you were fast!


dan
2018-11-13 21:02:08

@pocmatos can you change your program to something like this? #lang typed/racket (define sha1sum (or (find-executable-path "sha1sum") (error "no exe"))) (define-values (proc out in err) (subprocess #f #f #f sha1sum))


pnwamk
2018-11-13 21:02:20
#lang typed/racket

(let ()
  (define sha1sum
    (find-executable-path "sha1sum"))

  (cond
    [(not sha1sum) (error "no exe")]
    [else
     (define-values (proc out in err)
       (subprocess #f #f #f sha1sum))

     (void)]))

pocmatos
2018-11-13 21:02:24

happy with this: #lang typed/racket (define sha1sum (find-executable-path "sha1sum")) (define-values (proc out in err) (if sha1sum (subprocess #f #f #f sha1sum) (error "no exe")))


pocmatos
2018-11-13 21:02:28

makes no sense to me.


pnwamk
2018-11-13 21:02:36

that works, so it must be that the unless is expanding into something Typed Racket can’t figure out


pnwamk
2018-11-13 21:02:51

macros expand, often when they fail to type check it initially makes no sense


pocmatos
2018-11-13 21:03:09

Thanks all for the work arounds… it would be great if Typed Racket could do the original though.


lexi.lambda
2018-11-13 21:05:56

It looks like TR is confused by the internal definition. This works: (define (f [x : (U #f String)]) (unless x (error "bad")) (ann x String)) This does not: (define (f [x : (U #f String)]) (unless x (error "bad")) (define y (ann x String)) y)


lexi.lambda
2018-11-13 21:07:46

It does not appear to be a Racket 7 regression, since the behavior is consistent on older versions of Racket, too.


pocmatos
2018-11-13 21:10:13

shame! @samth do we need a bug report?


samth
2018-11-13 21:16:55

TR reasons about sequencing in begin but not in letrec-values and the second expression is (letrec-values ([() (unless x (error "bad"))] [(y) (ann x String)]) y)


samth
2018-11-13 21:18:06

plumbing those effects through in the letrec code shouldn’t be too hard, I’d be happy to help if someone wants to take that on


pocmatos
2018-11-13 21:29:57

I would be interested in giving it a go if nobody picks it up but not before end of next week. I will get back to you on this in case it’s not sorted by then.


pocmatos
2018-11-13 21:30:26

How can I type define-values?


pocmatos
2018-11-13 21:30:42

I need so say: (define-values (authdata diff i) (place-channel-get ch))


pocmatos
2018-11-13 21:30:56

I know the type of message sent.


samth
2018-11-13 21:31:08
(: authdata ...)
(: diff ...)
(: i ...)
(define-values ...)

pocmatos
2018-11-13 21:33:05

Thanks


samth
2018-11-13 21:33:16

however, place-channel-get produces only one value, so I’m confused


pocmatos
2018-11-13 21:33:19

Interesting: Type Checker: type mismatch; mismatch in number of values expected: 3 values given: 1 value in: (place-channel-get ch)


pocmatos
2018-11-13 21:33:27

ah…


pocmatos
2018-11-13 21:34:08

my mistake. :slightly_smiling_face: the message is supposed to be a list of 3 values instead!


pocmatos
2018-11-13 21:38:42

Even though I say that the type of the message is (: msg (List String Exact-Positive-Integer Nonnegative-Integer)) it’s telling me it should be any? Do I need some sort of Type assertion here to constrain the type?


samth
2018-11-13 21:44:44

place channels aren’t typed; they always return Any


pocmatos
2018-11-13 21:45:30

But how can I work with the result if I can’t tell typed racket what it is?


pocmatos
2018-11-13 21:45:56

I need to split the list into its components but with type Any I can’t really do much.


pocmatos
2018-11-13 21:46:22

I thought ann could help but doesn’t: (define msg (ann (place-channel-get ch) (List String Exact-Positive-Integer Nonnegative-Integer)))


samth
2018-11-13 21:47:41

ann just tells the type checker what you expect


samth
2018-11-13 21:48:04

you can use cast or you can write code with pair? etc


pocmatos
2018-11-13 21:48:59

ah, cast seems to be what I need. Not sure I understand the comment with regards to pair?


samth
2018-11-13 21:50:08

you can write (if (pair? msg) …)


pocmatos
2018-11-13 21:51:47

ah… ok, understood.


pocmatos
2018-11-13 21:51:49

Thanks.


pocmatos
2018-11-13 21:52:18

That’s where we need occurence typing, right?


samth
2018-11-13 21:53:22

yes


pocmatos
2018-11-13 21:59:46

Gosh, expecting massive speed up with so much typing. :wink:


pocmatos
2018-11-13 22:01:17

oh dear, maybe again I don’t understand polymorphic types but I have: (define job-evts (cast (apply choice-evt jobs) (Evtof Place))) (define solution (sync (handle-evt job-evts identity))) type checker says: Type Checker: Polymorphic function `handle-evt' could not be applied to arguments: Argument 1: Expected: (Evtof a) Given: (Evtof Place) Argument 2: Expected: (-> a b) Given: (All (a) (-> a a)) in: (handle-evt job-evts identity) but shouldn’t a be Place and b as well, due to the constrained imposed by identity? Not understanding it.


pocmatos
2018-11-13 22:29:25

ah, maybe I need inst


samth
2018-11-13 22:31:48

yes, that is likely the case


samth
2018-11-13 22:32:21

@pocmatos also, just so you know, unless your program spends almost all its time in numeric computation, it won’t see a big speedup from TR


pocmatos
2018-11-13 22:33:14

oh dear, I should be finished soon. but this one is mostly numerical computation. :slightly_smiling_face:


mpc.janssen
2018-11-13 22:44:36

@mpc.janssen has joined the channel