unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Shorter lambda expressions
@ 2014-01-23  4:51 Mark H Weaver
  2014-01-23  7:17 ` Mateusz Kowalczyk
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Mark H Weaver @ 2014-01-23  4:51 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 1446 bytes --]

Hello all,

For a short time I liked 'cut' from SRFI-26, but I soon became
frustrated by its limitations, most notably not being able to reference
the arguments out of order or within nested expressions.  I don't like
the inconsistent style that results when I use 'cut' wherever possible
and 'lambda' everywhere else.  So I just stopped using it altogether.

I prefer what Shiro Kawai did in Gauche: ^ is short for lambda, (^x ...)
is short for (lambda (x) ...), and similarly for all the letters.  ^_ is
short for lambda with one ignored argument.

  http://blog.practical-scheme.net/gauche/20100428-shorter-names

Here's a module that implements that idea, but takes it slightly
further.  It exports the unary lambda shorthands described above, and
also a few non-unary ones: ^xy, ^xyz, ^ab, ^abc, ^uv.  It also exports
variants that use λ instead of ^, for a nicer look if you're willing to
venture outside of ASCII.

Finally, it exports the transformer procedure that's bound to all of the
keywords above.  It's called 'short-lambda'.  Bind it to any keyword
like this:

  (define-syntax ^kw short-lambda)

and now (^kw ...) will expand to (lambda (k w) ...).

'short-lambda' splits the keyword into individual characters.  The first
character (usually ^ or λ) is ignored.  The other characters become the
variable names.  Underscores are treated specially: they become gensyms.

Thoughts?

    Mark



[-- Attachment #2: Short lambdas for Guile --]
[-- Type: text/plain, Size: 1460 bytes --]

(define-module (ice-9 short-lambdas)
  #:export (^ ^_ λ_
              ^a ^b ^c ^d ^e ^f ^g ^h ^i ^j ^k ^l ^m
              ^n ^o ^p ^q ^r ^s ^t ^u ^v ^w ^x ^y ^z
              ^xy ^xyz ^ab ^abc ^uv
              λa λb λc λd λe λf λg λh λi λj λk λl λm
              λn λo λp λq λr λs λt λu λv λw λx λy λz
              λxy λxyz λab λabc λuv
              short-lambda))

(eval-when (expand)
  (define short-lambda
    (lambda (form)
      (syntax-case form ()
        ((k-id body0 body ...)
         (let* ((k-symbol (syntax->datum #'k-id))
                (k-name   (symbol->string k-symbol))
                (chars    (cdr (string->list k-name)))
                (names    (map string chars))
                (symbols  (map string->symbol names)))
           (define (sym->id sym)
             (case sym
               ((_) (car (generate-temporaries '(_))))
               (else (datum->syntax #'k-id sym))))
           (with-syntax ((ids (map sym->id symbols)))
             #'(lambda ids body0 body ...))))))))

(define-syntax-rule (define-short-lambdas k ...)
  (begin (define-syntax k short-lambda) ...))

(define-short-lambdas
  ^ ^_ λ_
  ^a ^b ^c ^d ^e ^f ^g ^h ^i ^j ^k ^l ^m
  ^n ^o ^p ^q ^r ^s ^t ^u ^v ^w ^x ^y ^z
  ^xy ^xyz ^ab ^abc ^uv
  λa λb λc λd λe λf λg λh λi λj λk λl λm
  λn λo λp λq λr λs λt λu λv λw λx λy λz
  λxy λxyz λab λabc λuv)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
  2014-01-23  4:51 Mark H Weaver
@ 2014-01-23  7:17 ` Mateusz Kowalczyk
  2014-01-23  8:17 ` Panicz Maciej Godek
  2016-09-23 16:44 ` Panicz Maciej Godek
  2 siblings, 0 replies; 9+ messages in thread
From: Mateusz Kowalczyk @ 2014-01-23  7:17 UTC (permalink / raw)
  To: guile-devel

On 23/01/14 04:51, Mark H Weaver wrote:
> Hello all,
> 
> For a short time I liked 'cut' from SRFI-26, but I soon became
> frustrated by its limitations, most notably not being able to reference
> the arguments out of order or within nested expressions.  I don't like
> the inconsistent style that results when I use 'cut' wherever possible
> and 'lambda' everywhere else.  So I just stopped using it altogether.
> 
> I prefer what Shiro Kawai did in Gauche: ^ is short for lambda, (^x ...)
> is short for (lambda (x) ...), and similarly for all the letters.  ^_ is
> short for lambda with one ignored argument.
> 
>   http://blog.practical-scheme.net/gauche/20100428-shorter-names
> 
> Here's a module that implements that idea, but takes it slightly
> further.  It exports the unary lambda shorthands described above, and
> also a few non-unary ones: ^xy, ^xyz, ^ab, ^abc, ^uv.  It also exports
> variants that use λ instead of ^, for a nicer look if you're willing to
> venture outside of ASCII.
> 
> Finally, it exports the transformer procedure that's bound to all of the
> keywords above.  It's called 'short-lambda'.  Bind it to any keyword
> like this:
> 
>   (define-syntax ^kw short-lambda)
> 
> and now (^kw ...) will expand to (lambda (k w) ...).
> 
> 'short-lambda' splits the keyword into individual characters.  The first
> character (usually ^ or λ) is ignored.  The other characters become the
> variable names.  Underscores are treated specially: they become gensyms.
> 
> Thoughts?
> 
>     Mark
> 
> 

Hi,

Any chance for the curried version of these?

-- 
Mateusz K.



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
  2014-01-23  4:51 Mark H Weaver
  2014-01-23  7:17 ` Mateusz Kowalczyk
@ 2014-01-23  8:17 ` Panicz Maciej Godek
  2014-01-24 10:54   ` Ludovic Courtès
  2016-09-23 16:44 ` Panicz Maciej Godek
  2 siblings, 1 reply; 9+ messages in thread
From: Panicz Maciej Godek @ 2014-01-23  8:17 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-devel

Hi!

2014/1/23 Mark H Weaver <mhw@netris.org>:
> Hello all,
>
> For a short time I liked 'cut' from SRFI-26, but I soon became
> frustrated by its limitations, most notably not being able to reference
> the arguments out of order or within nested expressions.  I don't like
> the inconsistent style that results when I use 'cut' wherever possible
> and 'lambda' everywhere else.  So I just stopped using it altogether.
[...]

Before getting acquainted with SRFI-26, I came up with something
similar. It uses define-macro, because I didn't know syntax-case back
then, but I eventually stopped using it, since it was a little bit
confusing. It solved the problem by allowing numbered placeholders, so
e.g.
(\ + _1 _10) created a function of ten arguments which added its first
argument to its tenth argument, skipping all the others. There was
also a general placeholder, _, which behaved like SRFI-26's <>, so for
instance
(\ + _ _)
was an equivalent of
(\ + _1 _2)
but I eventually started to find it a little confusing, because the
same symbol refered to another entity.
Also the choice of symbol "\" was unfortunate, as it made the syntax
unportable among schemes (certain implementations would require to
write "\\" to get a backslash).

As far as I remember (I'd have to analyze the code to make sure), it
did support nested expressions. Also, after some time, I added another
placeholder ... for variadic arguments, which behaved more or less
like <...> form SRFI-26.

I think it would be best to extend SRFI-26 with the option of using
<1>, <2>, ... placeholders, where the resulting lambda would get the
arity indicated by the highest placeholder. Also, it should support
nested expressions.
Personally, I'd prefer it over the Gauche-style extension.

(define-macro (\ f . args)
  (let* ((prefix "_")
         (placeholder '_)
         (ellipsis '...)
         (rest (if (equal? (last args) ellipsis) ellipsis '()))
         (args (if (symbol? rest) (drop-right args 1) args))
         (max-arg 0)
         (next-arg
          (lambda ()
            (set! max-arg (+ max-arg 1))
            (string->symbol (string-append
                             prefix (number->string max-arg))))))
    (letrec ((process-arg
              (lambda(arg)
                (cond ((eq? arg placeholder)
                       (next-arg))
                      ((and-let*
                           (((symbol? arg))
                            (arg-string (symbol->string arg))
                            (match-struct (string-match
                                           (string-append
                                            "^"
                                            (regexp-quote prefix)
                                            "([0-9]+)$")
                                             arg-string))
                            (number (string->number
                                     (match:substring
                                      match-struct 1))))
                         (if (> number max-arg)
                             (set! max-arg number))
                         #t)
                       arg)
                      ((and (list? arg)
                            (not (null? arg))
                            (not (memq (first arg) '(\ quote))))
                       (map process-arg arg))
                      (else arg)))))
      (let ((args (map process-arg args)))
        `(lambda ,(append
                   (map (lambda (n)
                          (string->symbol
                           (string-append prefix (number->string n))))
                        (iota max-arg 1))
                   rest)
           ,(if (symbol? rest)
                `(apply ,f ,@args ,rest)
                `(,f ,@args)))))))



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
  2014-01-23  8:17 ` Panicz Maciej Godek
@ 2014-01-24 10:54   ` Ludovic Courtès
  2014-01-24 11:28     ` Taylan Ulrich Bayırlı/Kammer
  0 siblings, 1 reply; 9+ messages in thread
From: Ludovic Courtès @ 2014-01-24 10:54 UTC (permalink / raw)
  To: guile-devel

Panicz Maciej Godek <godek.maciek@gmail.com> skribis:

> I think it would be best to extend SRFI-26 with the option of using
> <1>, <2>, ... placeholders, where the resulting lambda would get the
> arity indicated by the highest placeholder. Also, it should support
> nested expressions.
> Personally, I'd prefer it over the Gauche-style extension.

I think I’d prefer this too, but actually I’m mostly satisfied with
SRFI-26.

One related thing I sometimes lack is:

  (define-syntax-rule (thunk exp ...)
    (lambda () exp ...))

(Found in Racket, notably.)

Ludo’.




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
  2014-01-24 10:54   ` Ludovic Courtès
@ 2014-01-24 11:28     ` Taylan Ulrich Bayırlı/Kammer
  2014-01-24 16:09       ` Mark H Weaver
  0 siblings, 1 reply; 9+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2014-01-24 11:28 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

ludo@gnu.org (Ludovic Courtès) writes:

> One related thing I sometimes lack is:
>
>   (define-syntax-rule (thunk exp ...)
>     (lambda () exp ...))

My understanding is that that'd be (^ exp ...).  `thunk' might be nicer
for one's tastes, but some consistency between different people's code
would be desired, so let me recommend sticking to ^ because:

* It's 4 characters shorter, which is a whole 1/20 (5%) of 80 columns!

* It's consistent with all the ^x etc.

I'm not entirely serious about the first point, though I do desire
consistency between people's code. :-)

Taylan



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
       [not found] <201401241138.s0OBc9u5025102@lambda.ccs.neu.edu>
@ 2014-01-24 13:28 ` Eli Barzilay
  0 siblings, 0 replies; 9+ messages in thread
From: Eli Barzilay @ 2014-01-24 13:28 UTC (permalink / raw)
  To: ludo

> One related thing I sometimes lack is:
>=20
>   (define-syntax-rule (thunk exp ...)
>     (lambda () exp ...))
>=20
> (Found in Racket, notably.)

IMO, it's much more useful to have `λ', together with an Emacs hack
that makes it easy to type.  In the last few years I even switched to
omitting the space in some simple cases, so I use

    (λ() (blah)
         (blah)
         (blah))

which is even shorter than `thunk'.  Also, there's no confusion
between `thunk' and `thunk*' (accepts any number of arguments) which
some people prefer.


(Not on the list; feel free to forward...)

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
  2014-01-24 11:28     ` Taylan Ulrich Bayırlı/Kammer
@ 2014-01-24 16:09       ` Mark H Weaver
  0 siblings, 0 replies; 9+ messages in thread
From: Mark H Weaver @ 2014-01-24 16:09 UTC (permalink / raw)
  To: Taylan Ulrich "Bayırlı/Kammer"
  Cc: Ludovic Courtès, guile-devel

[-- Attachment #1: Type: text/plain, Size: 776 bytes --]

taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") writes:

> ludo@gnu.org (Ludovic Courtès) writes:
>
>> One related thing I sometimes lack is:
>>
>>   (define-syntax-rule (thunk exp ...)
>>     (lambda () exp ...))
>
> My understanding is that that'd be (^ exp ...).

That's true given the code I posted, but it was not intentional.  I
meant to follow Gauche's convention that '^' is an alias for 'lambda',
so you'd need to type (^() exp ...) instead.

Another bug is that I should have used (expand load eval) in the
'eval-when'.

Finally, I've decided that it's nicer to export 'define-short-lambda'
than 'short-lambda'.

Here's an updated version.  More thoughts?  Alas, I guess this entire
topic is bikeshed territory :)

     Mark



[-- Attachment #2: Short lambdas for Guile v2 --]
[-- Type: text/plain, Size: 1636 bytes --]

(define-module (ice-9 short-lambdas)
  #:export (^ ^_ λ_
              ^a ^b ^c ^d ^e ^f ^g ^h ^i ^j ^k ^l ^m
              ^n ^o ^p ^q ^r ^s ^t ^u ^v ^w ^x ^y ^z
              ^xy ^xyz ^ab ^abc ^uv
              λa λb λc λd λe λf λg λh λi λj λk λl λm
              λn λo λp λq λr λs λt λu λv λw λx λy λz
              λxy λxyz λab λabc λuv
              define-short-lambda))

(eval-when (expand load eval)
  (define short-lambda
    (lambda (form)
      (syntax-case form ()
        ((k-id body0 body ...)
         (let* ((k-symbol (syntax->datum #'k-id))
                (k-name   (symbol->string k-symbol))
                (chars    (cdr (string->list k-name)))
                (names    (map string chars))
                (symbols  (map string->symbol names)))
           (define (sym->id sym)
             (case sym
               ((_) (car (generate-temporaries '(_))))
               (else (datum->syntax #'k-id sym))))
           (with-syntax ((ids (map sym->id symbols)))
             #'(lambda ids body0 body ...))))))))

(define-syntax-rule (define-short-lambda k)
  (define-syntax k short-lambda))

(define-syntax-rule (define-short-lambdas k ...)
  (begin (define-short-lambda k) ...))

(define-syntax-rule (^ formals body0 body ...)
  (lambda formals body0 body ...))

(define-short-lambdas
  ^_ λ_
  ^a ^b ^c ^d ^e ^f ^g ^h ^i ^j ^k ^l ^m
  ^n ^o ^p ^q ^r ^s ^t ^u ^v ^w ^x ^y ^z
  ^xy ^xyz ^ab ^abc ^uv
  λa λb λc λd λe λf λg λh λi λj λk λl λm
  λn λo λp λq λr λs λt λu λv λw λx λy λz
  λxy λxyz λab λabc λuv)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
  2014-01-23  4:51 Mark H Weaver
  2014-01-23  7:17 ` Mateusz Kowalczyk
  2014-01-23  8:17 ` Panicz Maciej Godek
@ 2016-09-23 16:44 ` Panicz Maciej Godek
  2016-09-24  9:38   ` Panicz Maciej Godek
  2 siblings, 1 reply; 9+ messages in thread
From: Panicz Maciej Godek @ 2016-09-23 16:44 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 797 bytes --]

I hope you don't mind me having dug this thread up, with an idea that is
only loosely related with the original one.

Recently I've been doing a small project in Clojure, and I've found that it
provides a function called "partial" that performs a sort of partial
application.

With guile's curried definitions, it can be defined as

(define ((partial function . args) . args+)
  (apply function `(,@args ,@args+)))

and it works rather nicely:

(map (partial cons 2) '((3 4) (3 5) (4 6) (7 1)))
===> ((2 3 4) (2 3 5) (2 4 6) (2 7 1))

I believe that -- since it is just a function -- it is much less
controversial than both the short macros and SRFI-26  (although its range
of applicability is narrower), and it seems to compose well with the spirit
of Scheme, so maybe that would be a nice-have?

[-- Attachment #2: Type: text/html, Size: 977 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Shorter lambda expressions
  2016-09-23 16:44 ` Panicz Maciej Godek
@ 2016-09-24  9:38   ` Panicz Maciej Godek
  0 siblings, 0 replies; 9+ messages in thread
From: Panicz Maciej Godek @ 2016-09-24  9:38 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 1697 bytes --]

2016-09-23 18:44 GMT+02:00 Panicz Maciej Godek <godek.maciek@gmail.com>:

> I hope you don't mind me having dug this thread up, with an idea that is
> only loosely related with the original one.
>
> Recently I've been doing a small project in Clojure, and I've found that
> it provides a function called "partial" that performs a sort of partial
> application.
>
> With guile's curried definitions, it can be defined as
>
> (define ((partial function . args) . args+)
>   (apply function `(,@args ,@args+)))
>
> and it works rather nicely:
>
> (map (partial cons 2) '((3 4) (3 5) (4 6) (7 1)))
> ===> ((2 3 4) (2 3 5) (2 4 6) (2 7 1))
>
> I believe that -- since it is just a function -- it is much less
> controversial than both the short macros and SRFI-26  (although its range
> of applicability is narrower), and it seems to compose well with the spirit
> of Scheme, so maybe that would be a nice-have?
>

I take it back.
It is a terrible idea. Using explicit lambda is a better solution, because
it gives an opportunity to provide a name for an element of a list. Yet the
name "partial" reads terribly. Compound usages such as

(partial map (partial cons 1))

are much worse than their regular counterparts, i.e.

(lambda (list)
  (map (lambda (element)
             (cons 1 element))
          list))

because even though the latter are more lengthy, this length actually
serves the purpose of exposing the structure of expression. In the former
case, it isn't clear (without knowing the arity of map) what will be the
arity of the whole expression, nor the role of those arguments. It seems to
be a problem even in the case of well-known functions such as cons or map.

Sorry for the noise

[-- Attachment #2: Type: text/html, Size: 2442 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-09-24  9:38 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <201401241138.s0OBc9u5025102@lambda.ccs.neu.edu>
2014-01-24 13:28 ` Shorter lambda expressions Eli Barzilay
2014-01-23  4:51 Mark H Weaver
2014-01-23  7:17 ` Mateusz Kowalczyk
2014-01-23  8:17 ` Panicz Maciej Godek
2014-01-24 10:54   ` Ludovic Courtès
2014-01-24 11:28     ` Taylan Ulrich Bayırlı/Kammer
2014-01-24 16:09       ` Mark H Weaver
2016-09-23 16:44 ` Panicz Maciej Godek
2016-09-24  9:38   ` Panicz Maciej Godek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).