helpful:   providing suggestions on unbound identifier error.
1 How to use it?
2 Suggestions
3 Examples
4 Limitations
5 API
#%top
5.1 Internals
suggest
6 More examples
8.12

helpful: providing suggestions on unbound identifier error.🔗ℹ

Sorawee Porncharoenwase <sorawee.pwase@gmail.com>

 (require helpful) package: helpful

This package provides suggestions on unbound identifier error. It requires Racket 8.7 at minimum.

1 How to use it?🔗ℹ

There are two ways to activate the suggestions.

2 Suggestions🔗ℹ

Currently, the package provides two kinds of suggestions.

One suggestion is hinting a “closest” identifier name, which could be helpful when the error is caused by a typo mistake. The definition of “closest” is according to the Levenshtein distance. It breaks a tie by the alphabetical order, with module and lexical bindings being prioritized over imported identifiers.

Another suggestion is hinting modules that could be imported to make the identifier bound, which could be helpful when you forgot to import the desired module. This feature consults Scribble and the Racket documentation index and thus is only available if they are installed.

3 Examples🔗ℹ

; Suggestion for a module binding
> (module test racket
    (require helpful)
    (define (fact x)
      (cond
        [(zero? x) 1]
        [else (* x (fac (sub1 x)))])))

eval:1:0: fac: unbound identifier

  in: fac

  suggestion: do you mean `fact'?

; Suggestion for a local binding
> (module test racket
    (require helpful)
    (define (fact x)
      (cond
        [(zero? x) 1]
        [else (* x (fact (sub1 y)))])))

eval:2:0: y: unbound identifier

  in: y

  suggestion: do you mean `x'?

; Suggestion for an imported identifier
> (module test racket
    (require helpful)
    (defun (fact) 1))

eval:3:0: defun: unbound identifier

  in: defun

  suggestion: do you mean `define'?

; Suggestion for a module to import
; (only when Scribble and the Racket documentation index are installed)
> (module test racket/base
    (require helpful)
    ->)

eval:4:0: ->: unbound identifier

  in: ->

  suggestion: do you mean `-'?

  alternative suggestion: do you want to import one of the

following modules, which provides the identifier?

   `lang/htdp-intermediate-lambda'

   `lang/htdp-intermediate'

   `ffi/unsafe'

   `lang/htdp-beginner-abbr'

   `mzlib/contract'

   `lang/htdp-advanced'

   `deinprogramm/sdp/beginner'

   `lang/htdp-beginner'

   `racket/contract/base' or `racket/contract' or `racket'

   `typed/racket/base' or `typed/racket'

4 Limitations🔗ℹ

The feature only affects code in a module or a #lang. Because top level is hopeless, the feature is disabled for the REPL.

The feature only works reliably for code at phase level 0.

5 API🔗ℹ

syntax

(#%top . x)

A replacement of Racket’s #%top that provides suggestions. A #lang that wishes to provide the suggestions by default can simply reprovide #%top.

5.1 Internals🔗ℹ

 (require helpful/suggest) package: helpful

procedure

(suggest x    
  [#:closest? closest?    
  #:import? import?])  none/c
  x : identifier?
  closest? : any/c = #t
  import? : any/c = #t
Given an unbound identifier x, this function raises the unbound id error with the suggestions. If closest? is #f, the closest identifier suggestion will be excluded. If import? is #f, the import suggestion will be excluded.

6 More examples🔗ℹ

; No suggestion outside a module or #lang
> (require helpful)
> (let ([x 1]) y)

y: undefined;

 cannot reference an identifier before its definition

  in module: top-level

; No suggestion for use-before-definition errors
> (module test racket
    (require helpful)
    an-id
    (define an-id #f))
> (require 'test)

an-id: undefined;

 cannot reference an identifier before its definition

  in module: 'test

; Prioritization of module/lexical bindings
> (module test racket
    (require helpful)
    (define add2 #f)
    (define add3 #f)
    add4)

eval:5:0: add4: unbound identifier

  in: add4

  suggestion: do you mean `add2'?

; Alphabetical order
> (module test racket
    (require helpful)
    (define add3 #f)
    (define add2 #f)
    add4)

eval:6:0: add4: unbound identifier

  in: add4

  suggestion: do you mean `add2'?

; Consistent with Racket
> (module test racket
    (require helpful)
    add2
    ())

eval:7:0: #%app: missing procedure expression;

 probably originally (), which is an illegal empty

application

  in: (#%app)

; Also consistent with Racket
> (module test racket
    (require helpful)
    add2
    (let () ()))

eval:8:0: add2: unbound identifier

  in: add2

  suggestion: do you mean `add1'?

; Another module recommendation
> (module test racket
    (require helpful)
    format-id)

eval:9:0: format-id: unbound identifier

  in: format-id

  suggestion: do you mean `format'?

  alternative suggestion: do you want to import

`racket/syntax', which provides the identifier?