Arc Forumnew | comments | leaders | submitlogin
Wish list.
1 point by ylando 5305 days ago | 13 comments
I am not a lisp programmer but I just discover lisp. I thing it is a great idea but I am not a common lisp or scheme fan.

Here is a wish list for thing i wish lisp has: I will be happy to know what your wish list too.

1) Mini languages in the core: A scope mini language were you can write some thing like { let x 3 ; print x } => (progn (let ((x 3)) print x)) a lambda scrope mini language { let x %1; print x} => (lambda (y) (let ((x y)) print y)) shortcuts in the scope mini language {let z arr[3]; print z} => (progn (let ((z (aref arr 3))) print z) Infix mini language and infix lambda mini language.

I wish you can declare strong and dynamic mode so it could be fast or dynamic.

If every instance of a class can have a macro: for example an array will have an each macro. We could use a statment like: (call arr each (x) (print x)) will print all element of an array it could be great. "(x)" will be the first argument of each and "(print x)" will be the second argument.

What do you thing about my ideas? What are your wish list?



3 points by rocketnia 5304 days ago | link

I think your ideas have merit, but first take a look at how your examples compare to what you can already do in Arc:

  { let x 3 ; print x }
  (let x 3 prn.x)        ; Note: "a.b" effectively means "(a b)"
  
  { let x %1; print x}
  [let x _ prn.x]       ; Note: "[a b c]" is like "(fn (_) (a b c))"
  
  {let z arr[3]; print z}
  (let z arr.3 prn.z)      ; Note: "(arr 3)" is like "(cadr (cddr arr))"
  
  (call arr each (x) (print x))
  (each x arr prn.x)
As for "infix mini language" and "infix lambda mini language," I've seen a couple of infix libraries floating around, and I'm pretty confident it would only take about a page of code to make one from scratch. Mini-languages like that are what a lisp is good for. ^_^ Also, while I initially missed having infix syntax when I started out with Scheme and Arc, I eventually forgot why. Prefix syntax just takes some getting used to, I think.

That said, I am enthusiastic about mini-languages. :)

I wish you can declare strong and dynamic mode so it could be fast or dynamic.

Hmm, curious. I'm not sure I can comment much as far as lisps are concerned, but I can say I've been considering using Groovy++ instead of (or alongside) Groovy for video processing (via the Xuggler JVM wrapper of ffmpeg) in the future, and Groovy++ is basically just Groovy with the ability to make exactly that kind of declaration. So I agree it's a nice feature. ^_^

In an Arc context, I'm not sure a strong/weak typing or static/dynamic dispatch distinction makes much sense, but on the other hand Arc might have its own declaration possibilities.

For instance, if you declare a variable to be constant, that variable value could be hardwired into every function that uses it (which is kinda what Jarc's compiler already does). This could eliminate the need to "dispatch" through 'ar-apply. (Er, just so you're not totally lost, ylando, Jarc is an unofficial Arc implementation in Java, and 'ar-apply is a Scheme function in the official Arc implementation which does function calls on functions while also doing useful function-call-like behaviors on non-functions. For instance, above I mentioned that (arr 3) is like (cadr (cddr arr)) in Arc, and 'ar-apply is what achieves that.)

-----

1 point by zck 5304 days ago | link

> 1) Mini languages in the core: A scope mini language were you can write some thing like { let x 3 ; print x } => (progn (let ((x 3)) print x)) a lambda scrope mini language { let x %1; print x} => (lambda (y) (let ((x y)) print y)) shortcuts in the scope mini language {let z arr[3]; print z} => (progn (let ((z (aref arr 3))) print z) Infix mini language and infix lambda mini language.

In Lisp, this would be a very bad idea to put in the core. There's no reason to do it. It should be built out of functions, macros, or read-macros. In fact, you can build it yourself!

> I wish you can declare strong and dynamic mode so it could be fast or dynamic.

I'm not sure what you're talking about here. Are you talking about Common Lisp's (declaim (optimize (speed 3)) statement?

> If every instance of a class can have a macro: for example an array will have an each macro. We could use a statment like: (call arr each (x) (print x)) will print all element of an array it could be great. "(x)" will be the first argument of each and "(print x)" will be the second argument.

Arc already has each! (http://files.arcfn.com/doc/iteration.html#each) Arc code to do your example is as follows:

  (each x arr
       (prn x))

-----

1 point by ylando 5304 days ago | link

Thank you for your answers.

When I talk about scope i meant a region where you can separate the function calls by a character, for example @ and the let statement span through all the region. You can easily write a macro that do (scope let x 2 @ let y 4 @ print (* x y) ) But it seem useful to me, why not have it in the core?

A class macro (this is how i call it) can be use to implement a more general case of ruby blocks in lisp. May be this idea has a problem of making a bloated binary code.

-----

1 point by zck 5304 days ago | link

Is

  (scope let x 2 @ let y 4 @ print (* x y) )
analogous to Common Lisp's let, or is it let* ?

I'm a little unclear as to what @ really does. What is the reason you want @? Is it just for let statements, or for any statement? Is it to make cleaner code, or for efficiency? Can you post some code that you think works better or is more elegantly written using @, rather than without it? Maybe some code of 5-10 lines?

-----

2 points by fallintothis 5303 days ago | link

I figure it's something like

  (mac scope exprs
    (trav exprs [if (caris _ '@)
                    (list (self (cdr _)))
                    (cons (car _) (self (cdr _)))]))
So then

  arc> (macex1 '(scope let x 2 @ let y 4 @ prn (* x y)))
  (let x 2 (let y 4 (prn (* x y))))
I think the idea is to reduce parentheses, but historically these sort of tricks don't seem to pan out.

-----

1 point by rocketnia 5303 days ago | link

I've actually wanted something similar from time to time, but without the '@ and 'let. Right now, I have just one place I really miss it (which you can see at http://github.com/rocketnia/lathe/blob/c343b0/arc/utils.arc), and that place currently looks like this:

  (=fn my.deglobalize-var (var)
    (zap expand var)
    (if anormalsym.var
      var
      
      ; else recognize anything of the form (global 'the-var)
      (withs (require     [unless _
                            (err:+ "An unrecognized kind of name was "
                                   "passed to 'deglobalize-var.")]
              nil         (do.require (caris var 'global))
              cdr-var     cdr.var
              nil         (do.require single.cdr-var)
              cadr-var    car.cdr-var
              nil         (do.require (caris cadr-var 'quote))
              cdadr-var   cdr.cadr-var
              nil         (do.require single.cdadr-var)
              cadadr-var  car.cdadr-var
              nil         (do.require anormalsym.cadadr-var))
        cadadr-var)
      ))
(Note that the Lathe library defines 'anormalsym to mean [and _ (isa _ 'sym) (~ssyntax _)]. Also, 'my is a Lathe namespace here, and I use Lathe's straightforward '=fn and '=mc to define things in namespaces. Finally, don't forget that (withs (nil 2) ...) binds no variables at all ('cause it destructures).)

If I define something like 'scope, I save myself a few parentheses and nils:

  (=mc my.scope body
    (withs (rev-bindings nil
            final nil
            acc [push _ rev-bindings])
      (while body
        (let var pop.body
          (if no.body
            (= final var)
              anormalsym.var
            (do do.acc.var (do.acc pop.body))
            (do do.acc.nil do.acc.var))))
      `(withs ,rev.rev-bindings ,final)))
  
  (=fn my.deglobalize-var (var)
    (zap expand var)
    (if anormalsym.var
      var
      
      ; else recognize anything of the form (global 'the-var)
      (my:scope
        require     [unless _
                      (err:+ "An unrecognized kind of name was passed "
                             "to 'deglobalize-var.")]
                    (do.require (caris var 'global))
        cdr-var     cdr.var
                    (do.require single.cdr-var)
        cadr-var    car.cdr-var
                    (do.require (caris cadr-var 'quote))
        cdadr-var   cdr.cadr-var
                    (do.require single.cdadr-var)
        cadadr-var  car.cdadr-var
                    (do.require anormalsym.cadadr-var)
                    cadadr-var)
      ))
Furthermore, I suspect this version of 'scope would almost always be preferable to 'do, 'let, and 'withs, partly because it's easier to refactor between those various cases. However, it doesn't do any destructuring, and it's probably a lot harder to pretty-print. (I'm not even sure how I would want to indent it in the long term.)

-----

2 points by fallintothis 5303 days ago | link

That example doesn't really call out to me: it looks like you could save yourself a few parentheses and nils by refactoring with something simpler, rather than with a complex macro. E.g., if I understand the code correctly:

  (=fn my.aglobal (var)
    (and (caris var 'global)
         (single:cdr var)
         (caris var.1 'quote)
         (single:cdr var.1)
         (anormalsym var.1.1)))

  (=fn my.deglobalize-var (var)
    (zap expand var)
    (if (anormalsym var)
         var
        (aglobal var)
         var.1.1
        (err "An unrecognized kind of name was passed to 'deglobalize-var.")))
But then, I avoid setting variables in sequence like that.

-----

2 points by rocketnia 5302 days ago | link

Hmm, I kinda prefer local variables over common subexpressions. It's apparently not for refactoring's sake, since I just name the variables after the way they're calculated, so it must just be a premature optimization thing. :-p

But yeah, that particular example has a few ways it can be improved. Here's what I'm thinking:

  (=fn my.deglobalize-var (var)
    (zap expand var)
    (or (when anormalsym.var var)
        (errsafe:let (global (quot inner-var . qs) . gs) var
          (and (is global 'global)
               (is quot 'quote)
               no.qs
               no.gs
               anormalsym.inner-var
               inner-var))
        (err:+ "An unrecognized kind of name was passed to "
               "'deglobalize-var.")))
I still like 'scope, but I'm fresh out of significant uses for it.

-----

2 points by fallintothis 5302 days ago | link

(To continue the digression into this particular case...) I had thought about destructuring, but found the need for qs and gs ugly. Really, a pattern matching library would be opportune. But since there's no such luck in Arc proper, it'd be ad-hoc and probably altogether not worth it (though not difficult to implement). I say this with respect to vanilla Arc; I don't know if Anarki has such a library. Still, it'd be hard to beat something like

  (=fn my.deglobalize-var (var)
    (zap expand var)
    (or (check var anormalsym)
        (when-match (global (quote ?inner-var)) var
          (check ?inner-var anormalsym))
        (err "An unrecognized kind of name was passed to 'deglobalize-var.")))

-----

2 points by akkartik 5304 days ago | link

I'm not sure I fully understand the features you're suggesting, but the question should be "does it have to be in the core". Err on the side of keeping the core as minimal as possible unless there is a clear reason to do otherwise.

-----

1 point by rocketnia 5303 days ago | link

Exactly. The core can't contain everything everybody would ever find useful. Instead, it's the core's job (IMO) to make it easy to define those things as they come up.

Additionally, it may or may not be the core's job to encourage canonical APIs for non-fundamental but really useful stuff, just so that programmers don't end up defining the same things over and over in ways that are flawed or incompatible with each other. I think this "may or may not" issue is the R7RS split in a nutshell.

In my own opinion, a "core" that tries to provide a comprehensive bookshelf of useful but programmer-definable things isn't a language; it's a utility library. Some libraries may be extremely popular, and they may even be standardized, distributed, and/or documented alongside their languages, but it's ultimately up to the development team to choose the combination of languages and libraries that's right for the project.

-----

2 points by ylando 5302 days ago | link

Here is my idea of scope implementation:

   (def split@ (lst (o acc)) 
      (if (empty lst) (list (rev acc)) 
         (caris lst '@) (cons (rev acc) (split@ (cdr lst)))
         (split@ (cdr lst) (cons (car lst) acc))))

  (def span_let (lst)
     (if (empty lst) ()
       (is (caar lst) 'let) 
             (list (append (car lst)
                           (span_let (cdr lst))))   
             (cons (car lst) (span_let (cdr lst))) ))

   (mac scope lst (cons 'do (span_let (split@ lst))))
But it will have a way of holding a list of binding functions and macros like let to make it more flexible. It will support scope inside scope.

-----

1 point by benneyquenue 5302 days ago | link

I am a web disigner. I want to add wishlist in my zencart eshop website.

-----