[racket users] %app question

39 views
Skip to first unread message

Kevin Forchione

unread,
Aug 13, 2020, 3:55:42 PM8/13/20
to Racket-Users List
Hi guys,

Pollen makes use of something like this:

(require syntax/parse/define)

(define-simple-macro (#%top . x) 'x)


and it comes in handy in some of my projects. But I’m wondering if there’s an equivalent for redirecting an application that hasn’t been defined?

In other words, if foo is not a procedure then (foo 1 2 3) would redirect to (do-this foo 1 2 3) where do-this is defined?

Any help is appreciated.

Thanks!

Kevin

Jens Axel Søgaard

unread,
Aug 13, 2020, 4:05:42 PM8/13/20
to Kevin Forchione, Racket-Users List
Hi Kevin,

In Bracket [1] used your idea to produce s-expression, if the first argument
of #%app isn't a function:

; In the BRACKET language an application of
  ; a non-function evaluates to an expression.
  (define-syntax (sym-app stx)
    (syntax-case stx ()
      [(_ op arg ...)
       (quasisyntax/loc stx
         (let ([o op])
           (if (procedure? o)
               #,(syntax/loc stx (#%app o arg ...))
               (if (holdable? o)
                   (cons o '(arg ...))
                   (cons o (list arg ...))))))]))

There is an additional wrinkle - if a function is "holdable" it "holds" (postpones) the 
evaluation of its arguments. This can simply we be removed, if you don't need it.

More details here:

https://github.com/soegaard/bracket/blob/master/bracket/bracket.rkt#L80

gfb

unread,
Aug 13, 2020, 6:51:54 PM8/13/20
to Racket Users
I'm not completely sure what you want, so the following handles both unbound identifiers in function position, as well as expressions in function position that have a value but the value is not a procedure. It delegates to a macro and a function respectively, that you can play with separately without fully understanding the main handler.

#lang racket

; We'll override ...
#;(f a ...) ; ... when f is not a macro, i.e. when this is by default a function call.

(module app-hook racket
 
  (provide (rename-out [our-app #%app]))
 
  (require syntax/parse/define)

  ; Will delegate to here at expansion time when f is an unbound identifier, for maximum control.
  (define-simple-macro (call-with-unbound f a ...)
    ; For example, you could ...
    (list 'f a ...))

  ; Will delegate to here at run time if f evaluates to a non-procedure.
  (define (call-with-non-procedure f . as)
    ; For example, you could ...
    (list* f as))

  (define-syntax-parser our-app
    [(_ f:id a ...)
     #:when (not (identifier-binding #'f))
     (syntax/loc this-syntax
       (call-with-unbound f a ...))]
    [(_ f a ...)
     (syntax/loc this-syntax
       (let ([f-value f]) ; standard macro side-effect safety : evaluate f expression only once
         (if (procedure? f-value)
             (f-value a ...)
             (call-with-non-procedure f-value a ...))))]))

(require 'app-hook)

(g (length '(a b c))) #;'(g 3)

(length (g '(a b c))) #;2

((+ 1 2) (+ 30 40 50)) #;'(3 120)

((println "once"))

; To Do (for an “industrial strength” version) : are we okay with the error messages from ...
#;()
#;(a . b)
#;(#:k)
#;((values 1 2))

Kevin Forchione

unread,
Aug 14, 2020, 11:43:48 AM8/14/20
to Jens Axel Søgaard, Racket-Users List
On Aug 13, 2020, at 1:05 PM, Jens Axel Søgaard <jens...@soegaard.net> wrote:

Den tor. 13. aug. 2020 kl. 21.55 skrev Kevin Forchione <lys...@gmail.com>:
Hi guys,

In Bracket [1] used your idea to produce s-expression, if the first argument
of #%app isn't a function:

; In the BRACKET language an application of
  ; a non-function evaluates to an expression.
  (define-syntax (sym-app stx)
    (syntax-case stx ()
      [(_ op arg ...)
       (quasisyntax/loc stx
         (let ([o op])
           (if (procedure? o)
               #,(syntax/loc stx (#%app o arg ...))
               (if (holdable? o)
                   (cons o '(arg ...))
                   (cons o (list arg ...))))))]))

There is an additional wrinkle - if a function is "holdable" it "holds" (postpones) the 
evaluation of its arguments. This can simply we be removed, if you don't need it.

More details here:

https://github.com/soegaard/bracket/blob/master/bracket/bracket.rkt#L80

Thanks! With a little modification that does the trick! 

Kevin
Reply all
Reply to author
Forward
0 new messages