Parsack: cannot reference an identifier before its definition

I wrote some code in Haskell that I'd like to translate in Racket. It's about Parsec and Parsack.

#lang racket

(require parsack)

(define quote-marks "'\"`")

(define quoted-name
  (between (oneOf quote-marks)
           (oneOf quote-marks)
           (many1 (noneOf quote-marks))))

(define not-found
  (>>= quoted-name
       (λ (name)
         (>> (>> $spaces
                 (string "not found"))
             (return (list->string name))))))

(define not-founds
  (choice
   (list
    (>> $eof
        (return '()))
    (try (>>= not-found
              (λ (name)
                (>>= not-founds
                     (λ (others) (return (cons name others)))))))
    (>> $anyChar
        not-founds))))

The error is:

not-founds: undefined;
 cannot reference an identifier before its definition

At first, I thought it was some typo within my code, but it isn't.

It seems that using >>= instead of >> makes the code work. I mean:

#lang racket

(require parsack)

(define quote-marks "'\"`")

(define quoted-name
  (between (oneOf quote-marks)
           (oneOf quote-marks)
           (many1 (noneOf quote-marks))))

(define not-found
  (>>= quoted-name
       (λ (name)
         (>> (>> $spaces
                 (string "not found"))
             (return (list->string name))))))

(define not-founds
  (choice
   (list
    (>> $eof
        (return '()))
    (try (>>= not-found
              (λ (name)
                (>>= not-founds
                     (λ (others) (return (cons name others)))))))
    ;; !!! here !!!
    (>>= $anyChar
        (λ (_) not-founds)))))

What am I missing here?

1 Like

You'll get the same error from (define a a).
Note that (define a (λ () a)) works.

The semantics of (define id expr) is more or less:

  1. Bind id to "the undefined value".
  2. Evaluate expr and get a value v.
  3. Assign v to id.

If during the evaluation of expr there is a reference to an undefined variable,
an error is thrown.

Try for example:

(define b (begin (display 1) b))

The usual fix of (define a a) is to use a thunk on the right hand side:

(define a (λ () a))

The lambda expression can be evaluated without evaluting any references to a,
so the error is avoided. Now a is a function, so when you refer to a write (a).

It's just one of the differences between a strict and lazy language that you get used to over time.

1 Like

Thank you for your time. I have been reading stuff these days, and I have tried to define (in my module) >> as a syntactic element (pardon my choice of words) rather than as a function.

(define-syntax-rule (>> f1 f2)
  (>>= f1 (λ (_) f2)))

Is this a solution, if I want to stick to Haskell for this piece of code? It seems to work, but I don't want it to mess with the library.