unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* (ice-9 nice-9) module update
@ 2015-09-02 12:09 Panicz Maciej Godek
  2015-09-02 13:08 ` Panicz Maciej Godek
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Panicz Maciej Godek @ 2015-09-02 12:09 UTC (permalink / raw)
  To: guile-user@gnu.org


[-- Attachment #1.1: Type: text/plain, Size: 809 bytes --]

As a follow-up to the thread
https://lists.gnu.org/archive/html/guile-devel/2015-06/msg00023.html I
announce that I made an update to the (ice-9 nice-9) module. It no longer
re-exports every, any and count, but instead it replaces two other bindings:

- define-syntax is now blended with define-syntax-rule, so that if one
writes

(define-syntax (name . pattern) . substitution)

the effect will be the same as if she wrote

(define-syntax name (syntax-rules () ((name .  pattern) . substitution)))

I think that there's no need to use "define-syntax-rule".

- let-syntax behaves similarly, i.e.

(let-syntax (((name . pattern) replacement)))
  ....)

transforms to

(let-syntax ((name (syntax-rules () ((name . pattern) replacement)))
  ....)

Any comments and suggestions are appreciated.

Best regards,
M.

[-- Attachment #1.2: Type: text/html, Size: 1226 bytes --]

[-- Attachment #2: nice-9.scm --]
[-- Type: text/x-scheme, Size: 5495 bytes --]

(define-module (ice-9 nice-9)
  #:use-module (ice-9 match)
  #:use-module ((srfi srfi-1) #:select (every))
  #:re-export (match)
  #:export ((and-let*/match . and-let*))
  #:replace ((cdefine . define)
	     (mlambda . lambda)
	     (named-match-let-values . let)
	     (match-let*-values . let*)
	     (let-syntax-rules . let-syntax)
	     (define-syntax/rule . define-syntax)))

(define-syntax define-syntax/rule
  (syntax-rules ()
    ((_ (name . pattern) . transformation)
     (define-syntax-rule (name . pattern) . transformation))
    ((_ name transformer)
     (define-syntax name transformer))))

(define-syntax let-syntax-rules
  (syntax-rules ()
    ((_ (bindings ...) body . *)
     (letrec-syntax ((let-syntax~
		      (syntax-rules ()
			((_ () ~processed-bindings ~body . ~)
			 (let-syntax ~processed-bindings ~body . ~))
			((_ (((~name ~pattern (... ...)) ~template)
			     ~bindings (... ...))
			    (~processed (... ...)) 
			    ~body . ~)
			 (let-syntax~
			  (~bindings (... ...))
			  (~processed (... ...)
				      (~name (syntax-rules () 
					       ((_ ~pattern (... ...))
						~template))))
			  ~body . ~))
			((_ ((~name ~value) ~bindings (... ...)) 
			    (~processed (... ...)) ~body . ~)
			 (let-syntax~ (~bindings (... ...)) 
				      (~processed (... ...) (~name ~value))
				      ~body . ~)))))
       (let-syntax~ (bindings ...) () body . *)))))

(define-syntax mlambda
  (lambda (stx)
    (syntax-case stx ()

      ((_ (first-arg ... last-arg . rest-args) body ...)
       (and (every identifier? #'(first-arg ... last-arg))
	    (or (identifier? #'rest-args) (null? #'rest-args)))
       #'(lambda (first-arg ... last-arg . rest-args) body ...))

      ((_ arg body ...)
       (or (identifier? #'arg) (null? #'arg))
       #'(lambda arg body ...))

      ((_ args body ...)
       #'(match-lambda* (args body ...)))
      )))

(define-syntax cdefine
  (syntax-rules ()
    ((_ ((head . tail) . args) body ...)
     (cdefine (head . tail)
       (mlambda args body ...)))
    ((_ (name . args) body ...)
     (define name (mlambda args body ...)))
    ((_ . rest)
     (define . rest))
    ))

(define-syntax list<-values
  (syntax-rules ()
    ((_ call)
     (call-with-values (lambda () call) list))))

(define-syntax named-match-let-values
  (lambda (stx)
    (syntax-case stx ()
      ((_ ((identifier expression) ...) ;; optimization: plain "let" form
	  body + ...)
       (every identifier? #'(identifier ...))
       #'(let ((identifier expression) ...)
	   body + ...))

      ((_ name ((identifier expression) ...) ;; optimization: regular named-let
	  body + ...)
       (and (identifier? #'name) (every identifier? #'(identifier ...)))
       #'(let name ((identifier expression) ...)
	   body + ...))

      ((_ name ((structure expression) ...)
	  body + ...)
       (identifier? #'name)
       #'(letrec ((name (mlambda (structure ...) body + ...)))
	   (name expression ...)))

      ((_ ((structure expression) ...)
	  body + ...)
       #'(match-let ((structure expression) ...) 
	   body + ...))

      ;; it should generally be discouraged to use the plain let
      ;; with multiple values, because there's no natural way to implement
      ;; that when there's more than one (multiple-value) binding,
      ;; but it's added for completeness
      ((_ ((structures ... expression) ...)
	  body + ...)
       #'(match-let (((structures ...) (list<-values expression)) ...)
	   body + ...))
      
      ((_ name ((structures ... expression) ...)
	  body + ...)
       (identifier? #'name) 
       #'(letrec ((loop 
		   (mlambda ((structures ...) ...)
			    (let-syntax ((name (syntax-rules ()
						 ((_ args (... ...))
						  (loop (list<-values args)
							(... ...))))))
			      body + ...))))
	   (loop (list<-values expression) ...)))
      )))

(define-syntax match-let*-values
  (lambda (stx)
    (syntax-case stx ()
      ((_ ((identifier expression) ...) ;; optimization: regular let*
	  body + ...)
       (every identifier? #'(identifier ...))
       #'(let* ((identifier expression) ...)
	   body + ...))
      
      ((_ ((structure expression) ...)
	  body + ...)
       #'(match-let* ((structure expression) ...)
	   body + ...))

      ((_ ((identifier expression) remaining-bindings ...)
	  body + ...)
       (identifier? #'identifier)
       #'(let ((identifier expression))
	   (match-let*-values (remaining-bindings ...) body + ...)))

      ((_ ((structure expression) remaining-bindings ...)
	  body + ...)
       #'(match-let ((structure expression))
	   (match-let*-values (remaining-bindings ...) body + ...)))
      
      ((_ ((structure structures ... expression) remaining-bindings ...)
	  body + ...)
       #'(call-with-values (lambda () expression) 
	   (mlambda (structure structures ...)
		    (let*-replacement (remaining-bindings ...) body + ...))))
      )))

(define-syntax and-let*/match
  (lambda (stx)
    (syntax-case stx ()

      ((_)
       #'#t)

      ((_ ())
       #'#t)

      ((_ () body ...)
       #'(let () body ...))

      ((_ ((value binding) rest ...) body ...)
       (identifier? #'value)
       #'(let ((value binding))
	   (and value
		(and-let*/match (rest ...)
				body ...))))

      ((_ ((value binding) rest ...) body ...)
       #'(match binding
	   (value
	    (and-let*/match (rest ...)
	      body ...))
	   (_ #f)))

      ((_ ((condition) rest ...)
	  body ...)
       #'(and condition
	      (and-let*/match (rest ...)
		body ...)))

      )))

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

* Re: (ice-9 nice-9) module update
  2015-09-02 12:09 (ice-9 nice-9) module update Panicz Maciej Godek
@ 2015-09-02 13:08 ` Panicz Maciej Godek
  2015-09-03 14:16   ` Panicz Maciej Godek
  2015-09-02 14:11 ` Taylan Ulrich Bayırlı/Kammer
  2015-09-02 14:48 ` Taylan Ulrich Bayırlı/Kammer
  2 siblings, 1 reply; 7+ messages in thread
From: Panicz Maciej Godek @ 2015-09-02 13:08 UTC (permalink / raw)
  To: guile-user@gnu.org

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

Also, I've just noted that now (ice-9 nice-9) exports only 8 bindings, so
there's surely a slot for defining some new ones.

Perhaps it would make sense to liberate letrec or letrec-syntax, so that it
would be possible to use it in a manner similar to let and letrec. However,
I don't think that using letrec in programs is ever a good taste. I'd
personally prefer to use internal "define", because it is much more
readable. As to letrec-syntax, there'd clearly be a little point in
defining recursive macros that have only a single syntax-rule clause.

Some time ago [1], I presented a following form:

(publish
 (define (f x) .... (g x) ....)
 where
 (define (g x)
   ....))

It is useful if one wants to define a few functions that are externally
visible, that share a common internal definition, but it also improves
readability when one defines even a single function that makes use of some
internal definitions. For example, I dare to claim that the usage shown
above is more readable than

(define (f x)
  (define (g x)
    ....)
  .... (g x) ....)

because the extent of internal definition is more apparent, and the body of
external definition is more concise. This is especially visible when there
are more internal definitions. If anyone's interested to see how the
publish-heavy code looks like, it can be viewed in [2].

So anyway, if anyone thinks that it could make sense, then I could add this
"publish" form to the (ice-9 nice-9) module, so that it would export
exactly 9 macros.

Or maybe anyone has a better idea?

[1] https://lists.gnu.org/archive/html/guile-user/2014-01/msg00002.html
[2]
https://bitbucket.org/panicz/slayer/src/cbfb3187edaba890b12b307d84bb9c4538407d20/tools/ply23d.scm?at=default

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

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

* Re: (ice-9 nice-9) module update
  2015-09-02 12:09 (ice-9 nice-9) module update Panicz Maciej Godek
  2015-09-02 13:08 ` Panicz Maciej Godek
@ 2015-09-02 14:11 ` Taylan Ulrich Bayırlı/Kammer
  2015-09-02 15:06   ` Panicz Maciej Godek
  2015-09-02 14:48 ` Taylan Ulrich Bayırlı/Kammer
  2 siblings, 1 reply; 7+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-09-02 14:11 UTC (permalink / raw)
  To: Panicz Maciej Godek; +Cc: guile-user@gnu.org

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

> As a follow-up to the thread
> https://lists.gnu.org/archive/html/guile-devel/2015-06/msg00023.html I
> announce that I made an update to the (ice-9 nice-9) module. It no
> longer re-exports every, any and count, but instead it replaces two
> other bindings:
>
> - define-syntax is now blended with define-syntax-rule, so that if one
> writes
>
> (define-syntax (name . pattern) . substitution)
>
> the effect will be the same as if she wrote
>
> (define-syntax name (syntax-rules () ((name . pattern) .
> substitution)))
>
> I think that there's no need to use "define-syntax-rule".
>
> - let-syntax behaves similarly, i.e.
>
> (let-syntax (((name . pattern) replacement)))
> ....)
>
> transforms to
>
> (let-syntax ((name (syntax-rules () ((name . pattern) replacement)))
> ....)
>
> Any comments and suggestions are appreciated.
>
> Best regards,
> M.

Maybe it would be good to make define and define-syntax more symmetric.
So if

    (define (foo . rest) . body)

is equivalent to

    (define foo (lambda rest . body)),

then

    (define-syntax (foo . rest) . body)

should perhaps be equivalent to

    (define-syntax (lambda rest . body)).

This is how Racket does it too, and one could say it's the most logical
and generalized choice.

It has one annoyance, which is that syntax transformers are only ever
passed one argument so the ability to use the argument list for
something more interesting is diminished, but I wonder if that's really
a big deal.  I prefer to keep things straightforward and consistent,
even if at the expense of forcing a little more verbosity (as long as
it's just a little).

Also, while it has that annoyance, it also has the advantage of allowing
you to do anything you want with that one syntax-object argument you
receive, e.g. passing it to syntax-case or (in the future) syntax-parse.
OTOH, making the argument list "special" will tie the form to a specific
macro system like syntax-rules or syntax-case, and also forbid using
multiple pattern/template pairs on it.  In my experience, using multiple
patterns is very common, and some code-bases also make heavy use of
syntax-case instead of syntax-rules, so I wouldn't allocate a primary
"syntax slot" like '(define-syntax (...) ...)' to something very
specific like "syntax-rules with one arm."

What do others think?  IMO using 'define-syntax-rule' for the
"syntax-rules with one pattern" special case is fine (and already
established), so I would say it's better to allocate 'define-syntax'
itself to the most generic use-case, like in Racket.

---

There are many possible extensions to 'let' (abbrev. for lambda, for
let-values, or for match-let), all of which make equally much sense to
me, so I think they're all bad, because no matter which one you
sanction, you will have discriminated against two others. :-)  Just keep
pure 'let' pure, and let people specify the exact variant they want...

However, for 'let-syntax' the situation is different.  There is no
let-syntax-values, and there is no match-let-syntax.  There is only one
way to use let-syntax, which is to bind the identifier to a syntax
transformer.  So I agree it's a good idea to extend it in that
direction.

That leaves the question of what sort of syntax transformer should be
created, syntax-rules or syntax-case or lambda, and the obvious choice
to me is to make it consistent with define-syntax, so in line with my
other recommendation, I would make

    (let-syntax (((foo stx) ...)) ...)

equivalent to

    (let-syntax ((foo (lambda (stx) ...))) ...).

And so the widest possible use-cases are covered.

Admittedly that slightly discriminates against syntax-rules, which
doesn't go well with the implicit lambda.  For that reason I would
propose a different syntax, similar to define-syntax-rule:

(let-syntax-rule
    (((foo x y)
      (do stuff))
     ((bar a b)
      (do stuff)))
  (body goes here))

This way everything is very consistent.  Define-syntax and let-syntax
are maximally generic and assume no specific macro system so one can
dispatch to the system of choice, the exception being syntax-rules which
requires there *not* to be a lambda, so for syntax-rules we define the
*-syntax-rule variants, and hopefully everyone is happy.

---

I also pondered on the following two, but note that each save merely a
single trivial line of code per syntax-rules invocation, so I think they
have little merit:

(define-syntax-rules foo ()
  ((_ x y)
   (do stuff))
  ((_ x y z)
   (do other stuff)))

(let-syntax-rules
    ((foo ()
      ((_ x y)
       (do stuff))
      ((_ x y z)
       (do other stuff)))
     (bar ()
      ((_ a b)
       (do stuff))
      ((_ a b c)
       (do other stuff))))
  (body goes here))

They're highly consistent with the rest though, so it shouldn't hurt
adding them if others think it's worth it.

---

That amounts to 6 cents, I hope it wasn't excessive. :-P

Taylan



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

* Re: (ice-9 nice-9) module update
  2015-09-02 12:09 (ice-9 nice-9) module update Panicz Maciej Godek
  2015-09-02 13:08 ` Panicz Maciej Godek
  2015-09-02 14:11 ` Taylan Ulrich Bayırlı/Kammer
@ 2015-09-02 14:48 ` Taylan Ulrich Bayırlı/Kammer
  2015-09-02 15:29   ` Panicz Maciej Godek
  2 siblings, 1 reply; 7+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-09-02 14:48 UTC (permalink / raw)
  To: Panicz Maciej Godek; +Cc: guile-user@gnu.org

Hmm, I just looked a bit closer into your other email:

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

> * blends named-let with match-let and srfi-71-style let for multiple
> values, legalizing usages like
>
> (let loop ((a (b c) (values 1 (list 2 3))))
>   ...
>   (loop (values 4 (list 5 6))))
>
> (although this may not seem to be a good way of programming, I think
> that imposing artificial limitations on how the language can be used
> would be even worse)

How does that one work?  AFAIUI, 'loop' would need to be a macro,
because otherwise you're returning multiple values to a single-value
continuation (<operand> slot of a procedure-call expression).

I haven't seen many uses of named-let where the name was being used for
anything else than directly calling it (though I have seen some, or at
least one, in GNU Guix's code), so maybe making it a macro would not be
too bad normally, but it goes against existing practice.

> * allows to destructure arguments to lambda, e.g.
>
> (map (lambda ((a . b)) (+ a b)) '((1 . 2) (3 . 4) (5 . 6)))
>
> [...]
>
> * allows to use curried definitions like (ice-9 curried-definitions),
> but such that are already blended with the pattern-matching lambda
>
> (define ((f (a b)) (c))
>   (list a b c))

Do you mean it allows currying *and* destructuring?  To be absolutely
honest, I would probably go mad while trying to read code using such a
feature. :-)

I'm not sure how often currying is used in Scheme.  Maybe it's just me;
do others use it occasionally?  I never felt like I needed such a
feature so far.  Would be a different thing is *all* procedures were
implicitly curried, but that's not the case...

If it's common to use currying in specific problem domains, such as
classical mechanics (since you mention SICM in the original email
starting this discussion), then IMO such extensions to 'define'
etc. should be kept private to code-bases working on such specialized
problem domains.  They shouldn't leak out to the general-purpose parts
of the language.

Supporting destructuring (and only that) in 'lambda' doesn't sound too
bad at face value, since I can't imagine many other possible semantics
for parenthesized forms in an argument list, but it worries me a bit
because then we will probably want to make 'let' consistent with
'lambda', and then we're again at the point where we discriminate
against other possible extensions to 'let'.

Therefore, in my opinion it's best to keep lambda and let pure, and just
use match-lambda, let-values, match-let, etc. where desired.  That's the
most "frictionless" way to go as I see it.


Sorry if I'm being negative in some regards.  All just my honest/blunt
opinions.

Taylan



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

* Re: (ice-9 nice-9) module update
  2015-09-02 14:11 ` Taylan Ulrich Bayırlı/Kammer
@ 2015-09-02 15:06   ` Panicz Maciej Godek
  0 siblings, 0 replies; 7+ messages in thread
From: Panicz Maciej Godek @ 2015-09-02 15:06 UTC (permalink / raw)
  To: Taylan Ulrich Bayırlı/Kammer; +Cc: guile-user@gnu.org

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

2015-09-02 16:11 GMT+02:00 Taylan Ulrich Bayırlı/Kammer <
taylanbayirli@gmail.com>:

>
> Maybe it would be good to make define and define-syntax more symmetric.
> So if
>
>     (define (foo . rest) . body)
>
> is equivalent to
>
>     (define foo (lambda rest . body)),
>
> then
>
>     (define-syntax (foo . rest) . body)
>
> should perhaps be equivalent to
>
>     (define-syntax (lambda rest . body)).
>
> This is how Racket does it too, and one could say it's the most logical
> and generalized choice.
>
>
That was my first guess, too, and so initially I did that the way you
described, but I eventually concluded that mapping

(define-syntax (s . args) . body)

as

(define-syntax s (syntax-rules () ((s . args) . body)))

is more analogous to mapping

(define (s . args) . body)

as

(define s (lambda args . body))

than (define-syntax s (lambda args . template))

This is because, at least in the substitutional model of computation, in
both define/lambda and define-syntax/syntax-rules case you can substitute
(s values ...) with body where the occurences of args in body are replaced
with values. Interpreting (define-syntax (s . args) . body) as
(define-syntax s (lambda args . body)) does not work that way, because, as
you noted, syntax transformers can take only a single argument, and -- more
importantly -- the argument doesn't say anything about how the macro is
intended to be used (it is, as Guile manual puts it, "a leaky
implementation detail").

I think that syntax-case or syntax-rules with many clauses resembles the
use of case-lambda more.

>
> Also, while it has that annoyance, it also has the advantage of allowing
> you to do anything you want with that one syntax-object argument you
> receive, e.g. passing it to syntax-case or (in the future) syntax-parse.
> OTOH, making the argument list "special" will tie the form to a specific
> macro system like syntax-rules or syntax-case, and also forbid using
> multiple pattern/template pairs on it.


Not forbid. This is just an extension of syntax that would otherwise be
illegal.
I agree that it is dubious that the interpretation ties itself to one macro
system, but this is the most commonly used macro system in Scheme. I agree
that there's an important difference between define-syntax+syntax-rules and
define+lambda -- namely, that the former has no intrinsic conditional like
"if".

  In my experience, using multiple
> patterns is very common, and some code-bases also make heavy use of
> syntax-case instead of syntax-rules, so I wouldn't allocate a primary
> "syntax slot" like '(define-syntax (...) ...)' to something very
> specific like "syntax-rules with one arm."
>
>
In my experience it is also very common, but interpreting (define-syntax
(name . args) ...) as (define-syntax name (lambda args ...)) doesn't
improve readability, and moreover might lead to confusion.

(define-syntax s (lambda (stx) (syntax-case stx () ...)))

is more explicit than

(define-syntax (s stx) (syntax-case stx () ...))

and the former should definitely be preferred over the latter, which would
only bring confusion and no improvement whatsoever


There are many possible extensions to 'let' (abbrev. for lambda, for
> let-values, or for match-let), all of which make equally much sense to
> me, so I think they're all bad, because no matter which one you
> sanction, you will have discriminated against two others. :-)


Well, no, actually there are only two reasonable extensions -- let-values
and match-let go together well, so the only one that can be discriminated
is the lambda (which would actually discriminate the perfectly-reasonable
srfi-71 let variant). And while I don't like the discrepancy between
pattern-matching let and syntax-ruling let-syntax, I don't think that
interpreting (let (((f x) '(1 2))) ...) as (let ((f (lambda (x) '(1 2))))
...) could actually be useful. But I do admit that it is only my personal
taste&experience. (I actually prefer to introduce internal function
definitions using the "define" form)

  Just keep
> pure 'let' pure, and let people specify the exact variant they want...
>
> However, for 'let-syntax' the situation is different.  There is no
> let-syntax-values, and there is no match-let-syntax.  There is only one
> way to use let-syntax, which is to bind the identifier to a syntax
> transformer.  So I agree it's a good idea to extend it in that
> direction.
>
> That leaves the question of what sort of syntax transformer should be
> created, syntax-rules or syntax-case or lambda, and the obvious choice
> to me is to make it consistent with define-syntax, so in line with my
> other recommendation, I would make
>
>     (let-syntax (((foo stx) ...)) ...)
>
> equivalent to
>
>     (let-syntax ((foo (lambda (stx) ...))) ...).
>
> And so the widest possible use-cases are covered.
>
> Admittedly that slightly discriminates against syntax-rules, which
> doesn't go well with the implicit lambda.  For that reason I would
> propose a different syntax, similar to define-syntax-rule:
>
> (let-syntax-rule
>     (((foo x y)
>       (do stuff))
>      ((bar a b)
>       (do stuff)))
>   (body goes here))
>
> This way everything is very consistent.  Define-syntax and let-syntax
> are maximally generic and assume no specific macro system so one can
> dispatch to the system of choice, the exception being syntax-rules which
> requires there *not* to be a lambda, so for syntax-rules we define the
> *-syntax-rule variants, and hopefully everyone is happy.
>
> ---
>
> I also pondered on the following two, but note that each save merely a
> single trivial line of code per syntax-rules invocation, so I think they
> have little merit:
>
> (define-syntax-rules foo ()
>   ((_ x y)
>    (do stuff))
>   ((_ x y z)
>    (do other stuff)))
>
> (let-syntax-rules
>     ((foo ()
>       ((_ x y)
>        (do stuff))
>       ((_ x y z)
>        (do other stuff)))
>      (bar ()
>       ((_ a b)
>        (do stuff))
>       ((_ a b c)
>        (do other stuff))))
>   (body goes here))
>
> They're highly consistent with the rest though, so it shouldn't hurt
> adding them if others think it's worth it.
>

Well, the define-syntax-rules and let-syntax-rules are non-controversial,
and I could even say that I like them a lot (especially let-syntax-rules).
My point, however, is to make things controversial, and to pick the right
interpretation for the formsthat otherwise wouldn't be legal.

So I think that it would be awesome to map

(let-syntax ((name keywords pattern . patterns))
   body)

to

(let-syntax ((name (syntax-rules keywords pattern . patterns)))
  body)

(and so forth)


>
> That amounts to 6 cents, I hope it wasn't excessive. :-P
>

I only have a dollar: $

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

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

* Re: (ice-9 nice-9) module update
  2015-09-02 14:48 ` Taylan Ulrich Bayırlı/Kammer
@ 2015-09-02 15:29   ` Panicz Maciej Godek
  0 siblings, 0 replies; 7+ messages in thread
From: Panicz Maciej Godek @ 2015-09-02 15:29 UTC (permalink / raw)
  To: Taylan Ulrich Bayırlı/Kammer; +Cc: guile-user@gnu.org

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

(sorry that I'm sending this for the second time, but it happened to me, as
frequently does, that I forgot to choose the "reply to all" option)

2015-09-02 16:48 GMT+02:00 Taylan Ulrich Bayırlı/Kammer<
taylanbayirli@gmail.com>:

> Hmm, I just looked a bit closer into your other email:
>
> Panicz Maciej Godek <godek.maciek@gmail.com> writes:
>
> > * blends named-let with match-let and srfi-71-style let for multiple
> > values, legalizing usages like
> >
> > (let loop ((a (b c) (values 1 (list 2 3))))
> >   ...
> >   (loop (values 4 (list 5 6))))
> >
> > (although this may not seem to be a good way of programming, I think
> > that imposing artificial limitations on how the language can be used
> > would be even worse)
>
> How does that one work?  AFAIUI, 'loop' would need to be a macro,
> because otherwise you're returning multiple values to a single-value
> continuation (<operand> slot of a procedure-call expression).
>
>
I didn't manage to figure out how the reference implementation of srfi-71
does that, but I indeed implemented that as you said, i.e. as a macro.


> I haven't seen many uses of named-let where the name was being used for
> anything else than directly calling it (though I have seen some, or at
> least one, in GNU Guix's code), so maybe making it a macro would not be
> too bad normally, but it goes against existing practice.
>

It only becomes a macro in the most general case, and not in the most
typical ones, so I guess that's not a big issue, but I do agree that
there's something untasteful in that. (But to be quite honest, I have
always been perceiving multiple values as an abuse)


> > * allows to destructure arguments to lambda, e.g.
> >
> > (map (lambda ((a . b)) (+ a b)) '((1 . 2) (3 . 4) (5 . 6)))
> >
> > [...]
> >
> > * allows to use curried definitions like (ice-9 curried-definitions),
> > but such that are already blended with the pattern-matching lambda
> >
> > (define ((f (a b)) (c))
> >   (list a b c))
>
> Do you mean it allows currying *and* destructuring?  To be absolutely
> honest, I would probably go mad while trying to read code using such a
> feature. :-)
>

Yes, it does look crazy, I agree. But I can see no other reason why it
shouldn't be possible in principle

I'm not sure how often currying is used in Scheme.  Maybe it's just me;
> do others use it occasionally?  I never felt like I needed such a
> feature so far.  Would be a different thing is *all* procedures were
> implicitly curried, but that's not the case...
>

Well, as I wrote in an earlier e-mail from that thread, this is just being
consequent with mapping

(define (f . args) . body)

to

(define f (lambda args . body))

I have to admit that do find the generalization useful from time to time.
Even the code that I just wrote for my own purpose looks like this:

(publish
 (define above? (line-relation positive?))
 (define below? (line-relation negative?))
 (define on? (line-relation zero?))
 where
 (define ((line-relation predicate) point line)
   (let (((direction . displacement) line))
     (predicate (cross direction (- point displacement)))))
 (define (cross a b)
   (- (* (real-part a) (imag-part b))
      (* (real-part b) (imag-part a))))
 )

BTW as you can see, I didn't dare to use currying and destructuring in
function header at the same time. Not because that wasn't impossible, but
because it wouldn't be obvious to the reader that (direction .
displacement) is a representation of a line.

If it's common to use currying in specific problem domains, such as
> classical mechanics (since you mention SICM in the original email
> starting this discussion), then IMO such extensions to 'define'
> etc. should be kept private to code-bases working on such specialized
> problem domains.  They shouldn't leak out to the general-purpose parts
> of the language.
>

Well, actually I don't think they interfere with anything.


> Supporting destructuring (and only that) in 'lambda' doesn't sound too
> bad at face value, since I can't imagine many other possible semantics
> for parenthesized forms in an argument list, but it worries me a bit
> because then we will probably want to make 'let' consistent with
> 'lambda', and then we're again at the point where we discriminate
> against other possible extensions to 'let'.
>
>
Yes!


> Therefore, in my opinion it's best to keep lambda and let pure, and just
> use match-lambda, let-values, match-let, etc. where desired.  That's the
> most "frictionless" way to go as I see it.
>
>
That's reasonable, and so I don't want to force anyone to the choices that
I made


> Sorry if I'm being negative in some regards.  All just my honest/blunt
> opinions.
>

You're kidding, I think that it's absolutely great :)
We clearly have different views, and so we both disagree with some of the
assumptions of the other side, but I like the rigidity of arguments used in
the discussion.

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

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

* Re: (ice-9 nice-9) module update
  2015-09-02 13:08 ` Panicz Maciej Godek
@ 2015-09-03 14:16   ` Panicz Maciej Godek
  0 siblings, 0 replies; 7+ messages in thread
From: Panicz Maciej Godek @ 2015-09-03 14:16 UTC (permalink / raw)
  To: guile-user@gnu.org

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

I inform that I eventually resigned from publishing the "publish" form, as
it might be considered too idiosyncratic to some (mostly in its
implementation).

It now exports exactly 9 bindings, 7 of which are the core bindings
(lambda, define, define-syntax, let, let*, let-syntax, letrec-syntax), one
which replaces the srfi-2 and-let* whith a pattern matching one, and one
which simply re-exports match from (ice-9 match).

The main novelty is that I allowed a new usage of define-syntax and
let*-syntax variants, as suggested by Taylan. In addition to

(define-syntax (foo a b)
  (bar b a))

(which can be used in place of "define-syntax-rule"), one can also use it as

(define-syntax new-syntax keywords
  (pattern template)
  ...)

which will expand to

(define-syntax new-syntax
  (syntax-rules keywords
    (pattern template)
    ...))

The same applies to let-syntax and letrec-syntax.

The latest version can be found here:
https://bitbucket.org/panicz/slayer/src/42956355fc0aaab3c5b4897be3e37bbbf7f0963b/guile-modules/ice-9/nice-9.scm?at=default

HF

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

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

end of thread, other threads:[~2015-09-03 14:16 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-02 12:09 (ice-9 nice-9) module update Panicz Maciej Godek
2015-09-02 13:08 ` Panicz Maciej Godek
2015-09-03 14:16   ` Panicz Maciej Godek
2015-09-02 14:11 ` Taylan Ulrich Bayırlı/Kammer
2015-09-02 15:06   ` Panicz Maciej Godek
2015-09-02 14:48 ` Taylan Ulrich Bayırlı/Kammer
2015-09-02 15:29   ` 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).