From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Israelsson Tampe Newsgroups: gmane.lisp.guile.user,gmane.lisp.guile.devel Subject: Re: and-let* is not composable? Date: Mon, 09 Sep 2013 22:26:54 +0200 Message-ID: <15322456.2mtMPoYDS9@warperdoze> References: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit X-Trace: ger.gmane.org 1378758442 16846 80.91.229.3 (9 Sep 2013 20:27:22 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Mon, 9 Sep 2013 20:27:22 +0000 (UTC) To: guile-user@gnu.org, guile-devel@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Mon Sep 09 22:27:27 2013 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1VJ83R-0006MR-5s for guile-user@m.gmane.org; Mon, 09 Sep 2013 22:27:25 +0200 Original-Received: from localhost ([::1]:53618 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJ83Q-0007Pf-NZ for guile-user@m.gmane.org; Mon, 09 Sep 2013 16:27:24 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:44545) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJ83C-0007P3-4o for guile-user@gnu.org; Mon, 09 Sep 2013 16:27:16 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VJ835-0000y2-7a for guile-user@gnu.org; Mon, 09 Sep 2013 16:27:10 -0400 Original-Received: from mail-lb0-x22b.google.com ([2a00:1450:4010:c04::22b]:47685) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJ834-0000xr-Qw; Mon, 09 Sep 2013 16:27:03 -0400 Original-Received: by mail-lb0-f171.google.com with SMTP id u14so5564383lbd.30 for ; Mon, 09 Sep 2013 13:27:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:user-agent:in-reply-to:references :mime-version:content-transfer-encoding:content-type; bh=OqFy74rOZ28wjnoHPWFs2po+y9tg8lG9sCKR7TS6h+A=; b=IFsu9UjwgKv8p9QD/4Dagka1T83FDZ+M+B56qWeQQQ4Pci5BgQ38H9oryXL5kKDH6l bqI1QDF5vJ48DUlaDol23W716q4Da2MViaTzkhY8X6r52KnX3jOTfYpGZNWkZ9PQS6X9 BrlY0FBMW2Xb1vSucKPLDuLkKtaPy56n4Hg9cwRyyV3RWnk0tMuzjEEN0IQGo3YmXQub aqKKJSbrtM0gtLrsVer83ka9hEj6NyC8WbQ3j57qVyQY/3HCICeDu6xkHPduL4ud0QdO JbucB9VTDM7qbNhYpeB3Xv9dfVdQ1OPsW4khuYnHlzXRV9cQbXoG9Ut4+ZlADKX/IBqO oKhQ== X-Received: by 10.112.0.242 with SMTP id 18mr17497562lbh.18.1378758421033; Mon, 09 Sep 2013 13:27:01 -0700 (PDT) Original-Received: from warperdoze.localnet (1-1-1-39a.veo.vs.bostream.se. [82.182.254.46]) by mx.google.com with ESMTPSA id w10sm6834002lbv.6.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 09 Sep 2013 13:26:59 -0700 (PDT) User-Agent: KMail/4.9.5 (Linux/3.5.0-30-generic; KDE/4.9.5; x86_64; ; ) In-Reply-To: X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:4010:c04::22b X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: guile-user-bounces+guile-user=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.user:10776 gmane.lisp.guile.devel:16617 Archived-At: First of all define-macro is asking for trouble. don't use it is the general recomendation for guile. If you look into the kanren soures you will find, (define-syntax lambda@ (syntax-rules () ((_ (formal) body0 body1 ...) (lambda (formal) body0 body1 ...)) ((_ (formal0 formal1 formal2 ...) body0 body1 ...) (lambda (formal0) (lambda@ (formal1 formal2 ...) body0 body1 ...))))) (define-syntax @ (syntax-rules () ((_ rator rand) (rator rand)) ((_ rator rand0 rand1 rand2 ...) (@ (rator rand0) rand1 rand2 ...)))) That is currying where lambda@ is your define-curried and @ is the application of curried functions in a convinient way e.g. (test-check 'test-@-lambda@ (@ (lambda@ (x y z) (+ x (+ y z))) 1 2 3) 6) It's not what you wnt but this gives you a good pattern to maybe base your work on. If you still wan't to design defined curried ontop of syntax-rules I would recoment to use the ck macro e.g. (define-syntax ck (syntax-rules (quote) ((ck () 'v) v) ; yield the value on empty stack ((ck (((op ...) ea ...) . s) 'v) ; re-focus on the other argument, ea (ck-arg s (op ... 'v) ea ...)) ((ck s (op ea ...)) ; Focus: handling an application; (ck-arg s (op) ea ...)))) ; check if args are values (define-syntax ck-arg (syntax-rules (quote) ((ck-arg s (op va ...)) ; all arguments are evaluated, (op s va ...)) ; do the redex ((ck-arg s (op ...) 'v ea1 ...) ; optimization when the first ea (ck-arg s (op ... 'v) ea1 ...)) ; was already a value ((ck-arg s (op ...) ea ea1 ...) ; focus on ea, to evaluate it (ck (((op ...) ea1 ...) . s) ea)))) 1) define a partitioner, (a b c) -> (() a) ((a) b) ((a b) c)) with (define-syntax ck-partition (syntax-rules (quote) ((_ s '(a ... b) 'l) (ck-partition s '(a ...) '(((a ...) b) . l))) ((_ s '() 'l) (ck s 'l)))) 2) compile the pieces together (define-syntax compile-curried (syntax-rules (quote) ((_ s 'name '(a ...) 'body '(((b ...) c) ...)) (ck () '(define-syntax name (syntax-rules () ((_ a ...) (begin . body)) ((_ b ...) (lambda (c) (name b ... c))) ...)))))) 3) The overall macro (define-syntax-rule (define-curried (name a ...) . body) (ck () (compile-curried 'name '(a ...) 'body (ck-partition '(a ...) '())))) Now we need the definition of the ck macro, http://okmij.org/ftp/Scheme/macros.html We have it in guile also in master. So lets try it, ... scheme@(guile-user)> (define-curried (f a b c d) (list a b c d)) scheme@(guile-user)> (((f 1 2) 3) 4) $5 = (1 2 3 4) it works, lets try out the problematic vode you have, (use-modules (srfi srfi-2)) (use-modules (srfi srfi-1)) (define-curried (string-matches pattern string) (and-let* ((match-struct (string-match pattern string)) (count (match:count match-struct))) (map (lambda(n)(match:substring match-struct n)) (iota (1- count) 1)))) scheme@(guile-user)> (string-matches "([a-z])" "a") $4 = ("a") ,exp ((string-matches "([a-z])") "a") $5 = ((lambda (string-871) (let ((match-struct-876 (string-match "([a-z])" string))) (if match-struct-876 (let ((count-880 (match:count match-struct-876))) (if count-880 (map (lambda (n-883) (match:substring match-struct-876 n-883)) (iota (#{1-}# count-880) 1)) #f)) #f))) "a") And we see that string is not managed correctly. Is this a bug? I can't understand why this is not treated as intended! > On Monday, September 09, 2013 07:35:16 PM Panicz Maciej Godek wrote: > Hi, > some time ago I posted to comp.lang.scheme with the > following proposal of "define-curried" macro: > > (define-macro (define-curried signature . body) > (match signature > ((name args ...) > `(define-syntax ,name > (syntax-rules () > ((_ ,@args) > (begin ,@body)) > ,@(let loop ((args* args)) > (match args* > (() '()) > ((first ... last) > (cons `((_ ,@first #;...) > (lambda(,last)(,name ,@args*))) > (loop first #;...)))))))))) > > The idea was to expand, e.g. (define-curried (f a b c d) (list a b c > d)) to: > > (define-syntax f > (syntax-rules () > ((_ a b c d) > (begin (list a b c d))) > ((_ a b c) > (lambda(d) > (f a b c d))) > ((_ a b) > (lambda(c) > (f a b c))) > ((_ a) > (lambda(b) > (f a b))) > ((_) > (lambda(a) > (f a))))) > > I asked whether it would be possible to write that code using > syntax-rules only, but I received no answer, not even a reprimend. I > used that code to implement a quite convinient macro (actually that > urge was my inspiration): > > (define-curried (matches? pattern x) > (match x > (pattern #t) > (else #f))) > > so that I could write > > (filter (matches? (two elements)) some-list) > > Recently, I tried to write a nicer interface to string-match, that > would allow me to extract parenthesized subexpressions easily. My > first guess was this: > > (define-curried (string-matches pattern string) > ;;CAUTION: buggy version > (and-let* ((match-struct (string-match pattern string)) > (count (match:count match-struct))) > (map (lambda(n)(match:substring match-struct n)) > (iota (1- count) 1)))) > > and although it worked with a complete list of arguments, > (string-matches "([a-z])" "a") > ==> ("a") > it failed to curry properly > ((string-matches "([a-z])") "a") > ==> some strange error > > It turned out, that the "string" symbol doesn't get tied > with the lambda argument: > > (expand (string-matches "([a-z])")) > ==> > (lambda (string-12552) > (let ((match-struct-12557 (string-match "([a-z])" string))) > ;; the reason of our tears and despair is right here^^^ > (if match-struct-12557 > (let ((count-12561 (match:count match-struct-12557))) > (if count-12561 > (map (lambda (n-12564) > (match:substring match-struct-12557 n-12564)) > (iota (#{1-}# count-12561) 1)) > #f)) > #f))) > > This forced me to write another definition of string-matches > that doesn't use the and-let* macro and works as expected: > > (define-curried (string-matches pattern s) > (let ((match-struct (string-match pattern s))) > (if match-struct > (let ((count (match:count match-struct))) > (map (lambda(n)(match:substring match-struct n)) > (iota (1- count) 1))) > #f))) > > Nevertheless I am a little worried that either my macro, > or and-let* is not composable. Perhaps there's some wise > man here who knows what's going on. > > Best regards, > M.