I'm following realm of racket. The code below throws the following error:
coord-lat: contract violation
expected: coord?
given: #<void>
fly-ufo.rkt
#lang racket
(require 2htdp/universe 2htdp/image)
(struct coord (alt lat) #:transparent #:mutable)
(define WIDTH 400)
(define HEIGHT 400)
(define UFO *some_picture*)
(define (move-ufo pos)
(place-image/align UFO
(coord-alt pos)
(coord-lat pos)
"left" "top"
(empty-scene WIDTH HEIGHT)))
(define (increment pos)
(set-coord-alt! pos (+ 2 (coord-alt pos)))
(set-coord-lat! pos (+ 1 (coord-lat pos))))
(define (at-the-border pos)
(>= (coord-lat pos) (- HEIGHT 20)))
(big-bang (coord 0 0)
(on-tick increment)
(to-draw move-ufo)
(stop-when at-the-border))
Adding a (coord? pos)
conditional for debug affirmates that the coordinate is not a coord. Defining the current-state as a coord before the big-bang function as below also didn't solve the error:
(define s (coord 0 0))
(big-bang s...
I checked racket contract and struct documents, but couldn't find the cause. Since many examples used define-struct
, I also tried it and make-coord
, but this also didn't help. Racket document also suggest that struct is preferred.
Adding a contract to the coord
(provide coord)
(define-struct/contract coord ([alt number?]
[lat number?])
#:transparent
#:mutable)
causes the following error:
coord-lat: contract violation
expected: coord?
given: #<void>
in: the 1st argument of
(-> coord? number?)
contract from: (struct coord)
blaming: fly-ufo.rkt
at: fly-ufo.rkt
What may be the cause of the error here?
EDIT
@Greg Hendershott: set-coord-alt! is in the struct document of racket as:
set-id-field-id!, for each field that includes a #:mutable option, or when the #:mutable option is specified as a struct-option; a mutator procedure that takes an instance of the structure type and a new field value. The structure is destructively updated with the new value, and #<void>
is returned.
So, when I read the last sentence, I got why the function returns #<void>
, which I somehow missed before. So, in order to return a coord instead of a #<void>
, I added a pos
in the end of the increment function:
(define (increment pos)
(set-coord-alt! pos (+ 2 (coord-alt pos)))
(set-coord-lat! pos (+ 1 (coord-lat pos)))
pos)
and it worked.
2nd EDIT
I'm putting this just for future reference. After Metaxal noted that one should create a new struct, I updated the struct as follows:
;; a struct for the current state, where:
;; field 1 is x coordinate
;; field 2 is y coordinate
;; field 3 is horizontal speed
;; field 4 is vertical speed
(struct cs (lat alt hspeed vspeed))
and thereafter, stopping the ufo became as simple as:
(define (stop ufo)
(cs (cs-lat ufo) (cs-alt ufo) 0 0))
and speeding upwards became:
(define (up-wards ufo)
(cond [(> (cs-vspeed ufo) (- MAX-SPEED))
(struct-copy cs ufo [vspeed (sub1 (cs-vspeed ufo))])]
[#t (play-sound some-sound-file #t)
ufo]))
Now the only thing I wonder is, whether it is imperative style to put play-sound-file
and ufo
in a cascade in the else branch.
#:mutable
keyword in the struct definition, and in yourincrement
function you should create a new pos (which is actually simpler than mutating one, here). – Metaxalstruct-copy
. Simply(define (increment pos) (coord (coord-alt pos) (coord-lat pos)))
should do the job. But if you do want to experiment withstruct-copy
(which is indeed better if the struct is complicated), I think the standard docs should be helpful, if you haven't found them yet: docs.racket-lang.org/reference/struct-copy.html – Metaxal