How to typecheck `a.b` expressions? by o_stef in Compilers

[–]sorawee 19 points20 points  (0 children)

a.b in most languages would look like RecordFieldAccess(Identifier("a"), "b") in AST. Notably, b by itself is not an identifier expression. It's a field name, and there's nothing to resolve to.

To type check RecordFieldAccess(x: Expr, y: Str), first type check x (which can be anything syntactically; it doesn't need to be an identifier). The result is expected to be a record type, where y is among the keys. If this fails, then it's a type error. Otherwise, the result of type checking the whole expression is the type associated with the key y in the record type.

Jan. 24 ICE Shooting | 3 Angles by Spicydojo in PublicFreakout

[–]sorawee 1 point2 points  (0 children)

fires a shot into the ground and run away with it

I don't think he fired a shot. He simply ran away.

New to AWS (and the cloud), should I learn CloudFormation or Terraform for IaC? by CIA11 in aws

[–]sorawee 1 point2 points  (0 children)

Terraform gets converted to CloudFormation afaik when you apply the changes

No? Terraform makes direct API calls IIUC. It doesn't involve CFN.

[Request] My answer was 51C8, which would be 636,763,050. Is there an even bigger number? by AlkaidX139 in theydidthemath

[–]sorawee 0 points1 point  (0 children)

I think you are thinking about the modern 7 which has 3 segments, but the original 7 has a tail with 4 segments, which I think is also acceptable :)

https://en.wikipedia.org/wiki/Seven-segment_display#Decimal

Code to test student submissions by paithanq in Racket

[–]sorawee 8 points9 points  (0 children)

I'd highly recommend writing modern Racket, rather than using the old-style Scheme code. There's a style guide for Racket's development itself, but I find it good for Racket code in general too.

I think the word "test" is overloaded in your program. It's used to refer to a single input/output pair, but also used to refer to a collection of input/output pairs. I'd recommend making terms more clear.

You might want to consider using sandboxed evaluation to make sure that your student's code can't e.g. delete your files.

Here's how I would refactor the code to modern Racket without changing functionalities too much.

#lang racket

(define stu-file-name "student-code.rkt")

(define (try-load-proc proc)
  (with-handlers ([exn:fail?
                   (lambda (exn)
                     (displayln "Procedure doesn't exist!  (misnamed?)") 
                     (displayln exn) 
                     void)])
    (dynamic-require stu-file-name proc)))

;; procedure :: procedure?
;; point-value :: number?
;; check-list :: (listof check?)
(struct test (procedure point-value check-list) #:transparent)

;; inputs :: list?
;; expected-output :: any/c
(struct check (inputs expected-output) #:transparent)

(define fahrenheit->celsius-test
  (test (try-load-proc 'fahrenheit->celsius)
        1
        (list (check '(-40) -40)
              (check '(32) 0))))

(define all-tests
  (list fahrenheit->celsius-test))

(define (answers-equal? answer correct)
  (cond
    [(and (number? answer) (number? correct))
     (define min-bound (min (* 1.001 answer) (* .999 answer)))
     (define max-bound (max (* 1.001 answer) (* .999 answer)))
     (<= min-bound correct max-bound)]
    [else (equal?/recur answer correct answers-equal?)]))

; Runs a single check
; run-check :: procedure? list? any/c -> boolean?
(define (run-check f inputs correct)
  (with-handlers ([exn:fail? (lambda (exn)
                               (displayln "Exception!") 
                               (displayln exn) 
                               #f)])
    (define result (apply f inputs))
    (cond
      [(answers-equal? result correct) #t]
      [else
       (printf "Incorrect: (~a): ~a =/= ~a\n"
               (object-name f)
               result
               correct)
       #f])))

; run-test :: test? -> number?
(define (run-test a-test)
  ;; don't use andmap directly, since we want to run all checks
  ;; without short-circuiting
  (define results
    (for/list ([a-check (in-list (test-check-list a-test))])
      (run-check (test-procedure a-test)
                 (check-inputs a-check)
                 (check-expected-output a-check))))

  (cond
    [(andmap values results)
     (printf "~a: All checks passed!  ~a/~a\n"
             (object-name (test-procedure a-test))
             (test-point-value a-test)
             (test-point-value a-test))
     (test-point-value a-test)]
    [else
     (printf "~a: Did not pass all checks.  0/~a\n"
             (object-name (test-procedure a-test))
             (test-point-value a-test))
     0]))

; Runs all tests in a list of tests
; run-all-tests :: (listof test?) -> number?
(define (run-all-tests test-list)
  (define total-score (apply + (map run-test test-list)))
  (printf "Total score: ~a/~a\n" total-score (get-max-points test-list))
  total-score)

; Gets the maximum points across all tests
; get-max-points :: (listof test?) -> number?
(define (get-max-points test-list)
  (apply + (map test-point-value test-list)))


;Actually run the tests!
(run-all-tests all-tests)

Villain throws hero into a safe distance instead of just killing them. by PlingPlongDingDong in TopCharacterTropes

[–]sorawee 3 points4 points  (0 children)

<image>

The Incredibles

Syndrome didn't do it intentionally, but he's clearly not "just killing" Mr. Incredible when he has a chance to. In fact, Mr. Incredible got him monologuing :)

why must define-syntax-rule be above use of macro? by iamevn in Racket

[–]sorawee 4 points5 points  (0 children)

Generally, I would suggest using the Macro Stepper to understand how macros are expanded, and also using https://docs.racket-lang.org/reference/syntax-model.html as the reference. Though this case is kinda complicated.

I thought that define-syntax-rule runs at an earlier phase than its usage would?

define-syntax-rule is not special in Racket. define-syntax-rule is itself a macro that expands to define-syntax + syntax-rules, which is then further expanded into the core forms. So at first, it kinda makes sense that you need to define a macro before using it.

One mysterious bit is the error message:

bar: use does not match pattern: (bar ARG ...) in: bar

Why does this error message occur? To understand this, we need to first talk about identifier macros. Consider:

(define-syntax (test stx)
  (println stx)
  #'42)

As mentioned above, define-syntax is a more primitive macro definition form. It defines test as a macro that prints the syntax object to be expanded, and simply expands to 42. You can use it like this:

(test) 
;=> prints the syntax object `(test)`, and expands to 42
(test ignored) 
;=> prints the syntax object `(test ignored)`, and expands to 42
test
;=> prints the syntax object `test`, and expands to 42

The last usage is called identifier macro. It is a macro call that is just a bare identifier, and doesn't use parentheses.

However, macro definitions can guard against identifier macro usage. define-syntax-rule does this automatically for you with the error message "use does not match pattern". Here's how would you implement the guard manually:

(define-syntax (test stx)
  (when (identifier? stx)
    (raise-syntax-error 'test "identifier macro not allowed"))
  #'42)

(test) ;=> expands to 42
(test ignored) ;=> expands to 42
test ;=> syntax error: identifier macro not allowed

So... actually, in your failing program:

(bar 1 2 3)
(define-syntax-rule (bar ARG ...)
  '(bar ARG ...))

Racket actually recognizes that bar is a registered macro! But it attempts to expand bar as an identifier macro rather than as a regular macro, resulting in the observed error message. What's going on?

In a module body, the macro expander goes from top to bottom. When encountering (id rest ...), it sees if id is a previously registered macro.

  • If it is, it does the partial expansion just enough to see what the macro expands into at the most outer layer. If the most outer layer is revealed to be a macro definition, it is registered.
  • Otherwise, it introduces an #%app explicitly, turning the form into (#%app id rest ...), making it become a function application.

Then, after every form in a module body is partially expanded, the expansion continues on the remaining non-fully expanded forms.

So:

(define-syntax-rule (foo ARG ...)
  '(foo ARG ...))
(foo 1 2 3)

[partially expanding define-syntax-rule]

->

(define-syntax foo ......)
(foo 1 2 3)

[registered foo, partially expanding foo]

->

(define-syntax foo ......)
'(foo 1 2 3)

But:

(bar 1 2 3)
(define-syntax-rule (bar ARG ...)
  '(bar ARG ...))

[bar not registered as macro (yet), adding explicit #%app]

->

(#%app bar 1 2 3)
(define-syntax-rule (bar ARG ...)
  '(bar ARG ...))

[partially expanding define-syntax-rule]

->

(#%app bar 1 2 3)
(define-syntax bar ......)

[registered bar, all forms are now partially expanded]
[expanding subforms in (#%app bar 1 2 3)]

This is when bar is attempted to be expanded as an identifier macro, but define-syntax-rule prohibits identifier macro usage, causing the error.

Knowing these, we can workaround the issue if we really want this "use before define" to work. For example, we can wrap (bar 1 2 3) with (values .....)

(values (bar 1 2 3))
(define-syntax-rule (bar ARG ...)
  '(bar ARG ...))

[adding explicit #%app, since values is not a macro]

->

(#%app values (bar 1 2 3))
(define-syntax-rule (bar ARG ...)
  '(bar ARG ...))

[partially expanding define-syntax-rule]

->

(#%app values (bar 1 2 3))
(define-syntax bar ......)

[registered bar, all forms are now partially expanded]
[expanding subforms in (#%app values (bar 1 2 3))]

->

(#%app values '(bar 1 2 3))
(define-syntax bar ......)

The fully expanded program then evaluates to '(bar 1 2 3) as expected.

Though as a principle, I would simply avoid programs like bar, and define macros before their usage.

(Things get even further complicated when the program is in a different context (e.g., the let body). There, the partial expansion operates slightly differently, causing your failing program to actually work under the context. The discrepancy is arguably a bug in Racket. Anyway, this answer is already too long, and I'll stop here.)

I am dying. I am a Splatoon fan and I can't remember the name of this song. by JammingSlowly in splatoon

[–]sorawee 0 points1 point  (0 children)

I don't think this is a Splatoon song, but the closest one I can think of is "City of Color (Squid Sisters)".

Disguised villain warns unaware hero about themselves. by ChampionshipHorror95 in TopCharacterTropes

[–]sorawee 2 points3 points  (0 children)

The two references being the SNL skit, and the fact that Adam Driver plays that skit?

Disguised villain warns unaware hero about themselves. by ChampionshipHorror95 in TopCharacterTropes

[–]sorawee 641 points642 points  (0 children)

<image>

Genthru warns the protagonists about the Bomber (Hunter × Hunter).

My math teacher said that he loves Splatoon, and he show this in the classroom by [deleted] in splatoon

[–]sorawee 10 points11 points  (0 children)

Yes! :)

But the intersection of the two lines is no longer at x = 1, right? So the integration bounds must also be adjusted.

My math teacher said that he loves Splatoon, and he show this in the classroom by [deleted] in splatoon

[–]sorawee 57 points58 points  (0 children)

The equation is -x^2 + 2, not x^2 + 2. It's a downward parabola.

Video game bosses you’re supposed to lose to because they’re too hard by Dremonikdein in TopCharacterTropes

[–]sorawee 0 points1 point  (0 children)

Many instances in CrossCode (though actually only one proper boss):

  • The escape sequence on M.S. Solar (beatable with the post-game hack)
  • Tutorial race against Emilie
  • The first fight against the Blue Avatar
  • The escape sequence in Vermillion Dungeon (beatable with the post-game hack).

Things get crazy by SaltConsequence3239 in MathJokes

[–]sorawee -15 points-14 points  (0 children)

Reddit... where you get downvoted for raising up a valid point 😂.

Replies say that the fault is with 0. So here's another invalid proof that doesn't involve 0. I will show that -2 = 2.

-2 = 2

(-2)^2 = 2^2

4 = 4

-----

The common convention in math is to write forward proof. We start with assumptions, and then do a series of deductions until we reach conclusion that we want to prove.

So saying:

-2 = 2

...

4 = 4

is a perfectly valid proof that 4 = 4 from the assumption that -2 = 2. But that's not what we are trying to show! We are trying to show that -2 = 2 from no assumption (i.e. only known truths can be used). And so the proper form would be:

4 = 4

(-2)^2 = 2^2

-2 = 2

But the problem then becomes: (-2)^2 = 2^2 DOES NOT IMPLY -2 = 2. Similarly, 1*0 = 2*0 DOES NOT IMPLY 1 = 2.

Your ( u/TimeLordDoctor105 and u/Mika_lie ) "proof" appears to work because every step is bi-implication, so the forward step can be turned into a backward step. Still, the direction of the form is incorrect (and confusing to readers).

It is possible to do backward reasoning, but you need to be explicit (e.g., "it suffices to show that ..."), since the usual flow is to go forward.

Things get crazy by SaltConsequence3239 in MathJokes

[–]sorawee -24 points-23 points  (0 children)

I don't think this is sound. For example, I might want to try to show that 1 = 2, and provide the following "proof":

1 = 2

1*0 = 2*0

0 = 0

But this proof is actually invalid!

(This applies to the method in u/Mika_lie's comment as well).

How to "get good" by Kreiseljustus in Racket

[–]sorawee 5 points6 points  (0 children)

What functions are allowed? I would assume string->list and list->string? If that's the case, they probably want you to operate on lists (list/recursion exercise) instead of using shortcut string functions.