I was recently hacking away on a function in FSM and found that adding or removing #:transparent from a struct definition caused the expression to evaluate to a different value. Without it, it goes into an infinite loop from what appears to be the set-member? within the when clause not functioning correctly, with it, it terminates to a value correctly.
I was hoping to see if anyone could notice anything that would cause this behavior or maybe there are semantics I’m not aware of regarding using #:transparent?
I extracted the code here, apologies for such a large reproduction example. Any smaller example I attempted to create for this failed to reproduce the issue:
#lang racket/base
(require racket/set
data/queue
racket/list)
;; Remove transparency to change value of the expression
(struct pda-stack (elems len) #:transparent)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(struct pda-config (state ci-len stack) #:transparent)
(struct pda-rule (from-state read-symb pop to-state push push-len pop-len) #:transparent)
(define EMP 'ε)
(define (apply-ndpda K sigma gamma start finals pdarules w)
(define visited-set (mutable-set))
(define tovisit (make-queue))
(define finals-set (list->seteq finals))
(define word-vec (list->vector w))
(define rules-structs
(for/list ([pdarule (in-list pdarules)])
(pda-rule (caar pdarule)
(cadar pdarule)
(if (eq? (caddar pdarule) EMP)
'()
(caddar pdarule))
(caadr pdarule)
(if (eq? (cadadr pdarule) EMP)
'()
(cadadr pdarule))
(if (eq? (cadadr pdarule) EMP)
0
(length (cadadr pdarule)))
(if (eq? (caddar pdarule) EMP)
0
(length (caddar pdarule))))))
(define (mk-pdatransition r c)
(pda-config (pda-rule-to-state r)
(if (eq? (pda-rule-read-symb r) EMP)
(pda-config-ci-len c)
(+ (pda-config-ci-len c) 1))
(pda-stack (append (pda-rule-push r) (drop (pda-stack-elems (pda-config-stack c)) (pda-rule-pop-len r)))
(+ (pda-stack-len (pda-config-stack c))
(- (pda-rule-push-len r)
(pda-rule-pop-len r))))))
(define (loop)
(cond [(queue-empty? tovisit) 'reject]
[else
(define config (dequeue! tovisit))
(define new-configs
(for/list ([rule (in-list rules-structs)]
#:when (and (eq? (pda-config-state config) (pda-rule-from-state rule))
(or (eq? EMP (pda-rule-read-symb rule))
(and (< (pda-config-ci-len config) (vector-length word-vec))
(eq? (vector-ref word-vec (pda-config-ci-len config))
(pda-rule-read-symb rule))))
(or (and (>= (pda-stack-len (pda-config-stack config)) (pda-rule-pop-len rule))
(equal? (pda-rule-pop rule)
(take (pda-stack-elems (pda-config-stack config))
(pda-rule-pop-len rule))))))
#:do [(define new-config (mk-pdatransition rule config))]
#:when (not (set-member? visited-set new-config)))
(set-add! visited-set new-config)
new-config))
(define accepts
(filter (lambda (c) (and (set-member? finals-set (pda-config-state c))
(= 0 (pda-stack-len (pda-config-stack c)))
(= (vector-length word-vec) (pda-config-ci-len c))))
(cons config new-configs)))
(cond [(not (null? accepts))
'accept]
[else
(for ([new-config (in-list new-configs)])
(enqueue! tovisit new-config))
(loop)])]))
(enqueue! tovisit (pda-config start 0 (pda-stack '() 0)))
(set-add! visited-set (pda-config start 0 (pda-stack '() 0)))
(loop))
(apply-ndpda '(s S M F)
'(a b)
'(a b)
's
'(s F)
'(((s ε ε) (S ε))
((F ε ε) (S ε))
((S ε ε) (M ε))
((M a ε) (M (a)))
((M b (a)) (M ε))
((M a (b)) (M ε))
((M b ε) (M (b)))
((M ε ε) (F ε)))
'(a))