[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: s-exprs + prototypes

James McCartney wrote:
> The reason I was asking about s-exprs:
> I'm toying with an object system for a Self-like prototype language
> using s-exprs as the syntax.
> The syntax for method calls is not prefix, it is (receiver selector
> ..args..).

Using PLT Scheme, it's very easy to implement a call syntax like this, which
could be useful for prototyping your language.  For example, it's easy to
redefine the low-level function application operator, which PLT calls #%app.
With only 7 lines of code, all the examples in your message can be
supported, and more.  Here goes:

  (module reverse-apply mzscheme

    ; define a "backwards" application operation
    (define-syntax reverse-apply
      (syntax-rules ()
        [(_ fn) (fn)]  ;support zero-arg calls
        [(_ obj fn arg ...) (fn obj arg ...)]))

    ; allow this module to be used as a "language" (see below)
    (provide (all-from-except mzscheme #%app)
             ; provide reverse-apply, replacing default #%app
             (rename reverse-apply #%app)))

Save the above in a file called "reverse-apply.scm".  To use this
interactively, at the Scheme prompt you can execute:

  (require "reverse-apply.scm")

Now you can do the following:

  (1 + 2)      ;==> 3
  ('a cons 'b) ;==> (a . b)
  ('(a b) car) ;==> a
  ('(a b) cdr) ;==> (b)

  ; some dummy definitions - note reversed syntax
  (define (filter x y) ("[filtering " string-append x y "] "))
  (define (merge x y) ("[merging " string-append x y "] "))
  (define (sort x) ("[sorting " string-append x "] "))

  (((("x" sort) merge "y") filter "z") display)
    ;==> [filtering [merging [sorting x] y] z]

  (define (mapmsg lst msg) ((lambda (e) (eval (cons e msg))) map lst))

  ('(1 2 3) mapmsg '(+ 20))
    ;==> (21 22 23)

Of course, this doesn't deal with prototype objects, but that's also quite

PLT allows you to take the above a step further and use the reverse-apply
module as the "language" which another module should use.  The syntax, which
is used above, is (module <module-name> <language> ...).  So, (module
test-reverse "reverse-apply.scm" ...) will ensure that everything in the
test-reverse module uses the reverse apply.  In this case, since only one
function is being redefined (#%app), and no other functions added or taken
away, this probably doesn't make much difference; but for realistic
languages, the module language feature provides a very useful capability,
since it prevents a module from using features other than those provided by
the specified language.

> I find
> 	(((data sort) merge x) filter y)
> more natural to read and write than
> 	(filter (merge (sort data) x) y)
> A preference that could just be due to my greater time with OOP instead
> of FP.

I think this preference comes entirely from OOP.  I also think it's worth
unlearning (I'm glad I did).  It's definitely not something to cling to if
you want to get into FP, but of course it can make sense for the kind of
language you're proposing.

> Perhaps some lispers might find this not the "right way"..
> Interested in opinions.

Once you set a paradigm for a language, such as that everything will be done
by sending messages to an object, subsequent decisions have to make sense
relative to the chosen paradigm.  It may not make sense to question these
decisions outside that context.

One issue that arises is whether the chosen paradigm is sufficiently general
or appropriate to all the intended applications of the language - not to
mention the unintended applications!  In most cases, the choice of paradigm
is unlikely to attract users to a language: for example, people don't use
Javascript because it's prototype-based or because it supports function
objects and closures, they use it because it's embedded in browsers.  Its
paradigm is really quite secondary.  A question to ask about a paradigm
you're choosing for a language, is what problems the paradigm is addressing,
and whether those problem can or should be addressed in a more
general-purpose way, without dedicating the entire language to a particular
way of doing things.