From: ········@gmail.com
Subject: Exported closure issue
Date: 
Message-ID: <1170996952.113746.112100@l53g2000cwa.googlegroups.com>
I'm attempting to provide a package, whose interface is defined by
'init' function.  Here's the package:

[snip]
(defpackage :indexer
  (:use     :cl)
  (:export  :init))

(in-package :indexer)
(provide    :indexer)

(load "config-parser.lisp")

(defun init (config)
  (let ((conf (config-parser:init config)))
    (lambda (action)
      (cond ((equal action 'a) "A")
                ((equal action 'b) "B")
                (t "Unknown action.")))))
[snip]

Now, at the REPL, if I attempt an action on the closure, it doesn't
work as expected.  An example session:

CL-USER> (load "indexer.lisp")
T
CL-USER> (setf (symbol-function 'test) (indexer:init "indexer.conf"))
#<FUNCTION (LAMBDA (INDEXER::ACTION)) {ACF116D}>
CL-USER> (test 'a)
"Unknown action."
CL-USER>

I'm new at this, so any insight as to what I'm doing incorrectly would
be most appreciated.  Thanks for your time.

From: ·······@gmail.com
Subject: Re: Exported closure issue
Date: 
Message-ID: <1171008818.290152.257590@h3g2000cwc.googlegroups.com>
On Feb 9, 5:55 am, ·········@gmail.com" <········@gmail.com> wrote:
> I'm attempting to provide a package, whose interface is defined by
> 'init' function.

This sounds as if you're a bit confused about what a package is.
PROVIDE has nothing to do with packages, and a package doesn't have an
interface.  Packages are first-class objects in Common Lisp, they are
explained for example here:

  http://www.gigamonkeys.com/book/programming-in-the-large-packages-
and-symbols.html

Your problem is related to packages, though:

> Here's the package:
>
> [snip]
> (defpackage :indexer
>   (:use     :cl)
>   (:export  :init))
>
> (in-package :indexer)
> (provide    :indexer)
>
> (load "config-parser.lisp")
>
> (defun init (config)
>   (let ((conf (config-parser:init config)))
>     (lambda (action)
>       (cond ((equal action 'a) "A")
>                 ((equal action 'b) "B")

Here you're testing for the symbols INDEXER::A and INDEXER::B.

>                 (t "Unknown action.")))))
> [snip]
>
> Now, at the REPL, if I attempt an action on the closure, it doesn't
> work as expected.  An example session:
>
> CL-USER> (load "indexer.lisp")
> T
> CL-USER> (setf (symbol-function 'test) (indexer:init "indexer.conf"))
> #<FUNCTION (LAMBDA (INDEXER::ACTION)) {ACF116D}>
> CL-USER> (test 'a)
> "Unknown action."

Here you are providing the symbol CL-USER::A (which is different from
INDEXER::A) as an argument.  Try

  (test 'indexer::a)

for example.  Or, as Lars said, rewrite the function to use keyword
symbols.
From: Lars Rune Nøstdal
Subject: Re: Exported closure issue
Date: 
Message-ID: <pan.2007.02.09.05.37.21.793947@gmail.com>
I'm gonna let someone else explain this properly, but replacing 'a and 'b
with :a and :b would fix this.

cl-user> (defpackage :indexer
           (:use :cl))
           
#<package "INDEXER">
cl-user> (in-package :indexer)
#<package "INDEXER">
indexer> 'abcd
abcd
indexer> (symbol-package 'abcd)
#<package "INDEXER">
indexer> (in-package :cl-user)
#<package "COMMON-LISP-USER">
cl-user> 'abcd
abcd
cl-user> (symbol-package 'abcd)
#<package "COMMON-LISP-USER">
cl-user> 
; No value
cl-user> (in-package :indexer)
#<package "INDEXER">
indexer> :dcba
:dcba
indexer> (symbol-package :dcba)
#<package "KEYWORD">
indexer> (in-package :cl-user)
#<package "COMMON-LISP-USER">
cl-user> :dcba
:dcba
cl-user> (symbol-package :dcba)
#<package "KEYWORD">
cl-user> (equal 'indexer::abcd 'abcd)
nil

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Andreas Thiele
Subject: Re: Exported closure issue
Date: 
Message-ID: <eqhrb8$o9r$03$1@news.t-online.com>
<········@gmail.com> schrieb im Newsbeitrag ·····························@l53g2000cwa.googlegroups.com...
> I'm attempting to provide a package, whose interface is defined by
> 'init' function.  Here's the package:
> 
> [snip]
> (defpackage :indexer
>  (:use     :cl)
>  (:export  :init))
> 
> (in-package :indexer)
> (provide    :indexer)
> 
> (load "config-parser.lisp")
> 
> (defun init (config)
>  (let ((conf (config-parser:init config)))
>    (lambda (action)
>      (cond ((equal action 'a) "A")
>                ((equal action 'b) "B")
>                (t "Unknown action.")))))
> [snip]
> 
> Now, at the REPL, if I attempt an action on the closure, it doesn't
> work as expected.  An example session:
> 
> CL-USER> (load "indexer.lisp")
> T
> CL-USER> (setf (symbol-function 'test) (indexer:init "indexer.conf"))
> #<FUNCTION (LAMBDA (INDEXER::ACTION)) {ACF116D}>
> CL-USER> (test 'a)
> "Unknown action."
> CL-USER>
> 
> I'm new at this, so any insight as to what I'm doing incorrectly would
> be most appreciated.  Thanks for your time.
>

Hi,

as already suggested, you should read more on packages. Keep in mind, that everything is very dynamic.

If you use a symbol 'a inside your package indexer, the symbol will be indexer::a. If you use 'a while in package cl-user the symbol is cl-user::a. Both are not equal (eq indexer::a cl-user::a) => nil.

provide is used in conjunction with require and should rather be the last line in your code. This way your module will only be provide if the source could be loaded without any error. It has got nothing to do with packages it is more for managing loading of source files.

Helpful reading on packages is also: http://www.flownet.com/gat/packages.pdf

Andreas
From: Andreas Thiele
Subject: Re: Exported closure issue
Date: 
Message-ID: <eqhrhe$ojr$03$1@news.t-online.com>
<········@gmail.com> schrieb im Newsbeitrag ·····························@l53g2000cwa.googlegroups.com...
> I'm attempting to provide a package, whose interface is defined by
> 'init' function.  Here's the package:
> 
> [snip]
> (defpackage :indexer
>  (:use     :cl)
>  (:export  :init))
> 
> (in-package :indexer)
> (provide    :indexer)
> 
> (load "config-parser.lisp")
> 
> (defun init (config)
>  (let ((conf (config-parser:init config)))
>    (lambda (action)
>      (cond ((equal action 'a) "A")
>                ((equal action 'b) "B")
>                (t "Unknown action.")))))
> [snip]
> 
> Now, at the REPL, if I attempt an action on the closure, it doesn't
> work as expected.  An example session:
> 
> CL-USER> (load "indexer.lisp")
> T
> CL-USER> (setf (symbol-function 'test) (indexer:init "indexer.conf"))
> #<FUNCTION (LAMBDA (INDEXER::ACTION)) {ACF116D}>
> CL-USER> (test 'a)
> "Unknown action."
> CL-USER>
> 
> I'm new at this, so any insight as to what I'm doing incorrectly would
> be most appreciated.  Thanks for your time.
>

I forgot, where is your closure? You bound conf but never used it, so I don't see a closure, just a lambda which could as well be an ordinary function for convenience in this case.

Andreas
From: Pascal Bourguignon
Subject: Re: Exported closure issue
Date: 
Message-ID: <87odo3wj2n.fsf@thalassa.informatimago.com>
·········@gmail.com" <········@gmail.com> writes:

> I'm attempting to provide a package, whose interface is defined by
> 'init' function.  Here's the package:
>
> [snip]
> (defpackage :indexer
>   (:use     :cl)
>   (:export  :init))
>
> (in-package :indexer)
> (provide    :indexer)
>
> (load "config-parser.lisp")
>
> (defun init (config)
>   (let ((conf (config-parser:init config)))
>     (lambda (action)
>       (cond ((equal action 'a) "A")
>                 ((equal action 'b) "B")
>                 (t "Unknown action.")))))

In the package INDEXER, when you read this DEFUN form, the symbol
named "A" is interned in the package INDEXER.  Therefore you are
comparing ACTION to the symbol INDEX::A.

> Now, at the REPL, if I attempt an action on the closure, it doesn't
> work as expected.  An example session:
>
> CL-USER> (load "indexer.lisp")
> T
> CL-USER> (setf (symbol-function 'test) (indexer:init "indexer.conf"))
> #<FUNCTION (LAMBDA (INDEXER::ACTION)) {ACF116D}>
> CL-USER> (test 'a)
> "Unknown action."
> CL-USER>
>
> I'm new at this, so any insight as to what I'm doing incorrectly would
> be most appreciated.  Thanks for your time.

In the package CL-USER (mind the prompt!), when you read (test 'a),
the symbol named "A" is  interned in the package CL-USER.  Therefore
you are giving to TEST the symbol CL-USER::A.

Now, let's see the rules for CL:EQUAL...

Symbols, Numbers, and Characters
   
    equal is true of two objects if they are symbols that are eq, if
    they are numbers that are eql, or if they are characters that are
    eql.
   
CL:EQUAL applied on two symbols is identical to CL:EQ.  Since you
having imported into CL-USER the symbol INDEXER:A to make both "path"
refer the same symbol, INDEXER::A and CL-USER::A are distinct, not EQ,
and not EQUAL.


So you have two choices:

- either export the symbols INDEXER:A and INDEXER:B, since obviously
  they are part of the interface!

- or test ACTION with STRING-EQUAL, which would allow you to pass any
  symbol named "A" or "a", or any string containing only the character
  #\A or #\a.  (or STRING= if you want case sensitivity).



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein
From: Andreas Thiele
Subject: Re: Exported closure issue
Date: 
Message-ID: <eqhu1f$uul$03$1@news.t-online.com>
"Pascal Bourguignon" <···@informatimago.com> schrieb im Newsbeitrag ···················@thalassa.informatimago.com...
> ·········@gmail.com" <········@gmail.com> writes:
> 
>> I'm attempting to provide a package, whose interface is defined by
>> 'init' function.  Here's the package:
>>
>> [snip]
>> (defpackage :indexer
>>   (:use     :cl)
>>   (:export  :init))
>>
>> (in-package :indexer)
>> (provide    :indexer)
>>
>> (load "config-parser.lisp")
>>
>> (defun init (config)
>>   (let ((conf (config-parser:init config)))
>>     (lambda (action)
>>       (cond ((equal action 'a) "A")
>>                 ((equal action 'b) "B")
>>                 (t "Unknown action.")))))
> 
> In the package INDEXER, when you read this DEFUN form, the symbol
> named "A" is interned in the package INDEXER.  Therefore you are
> comparing ACTION to the symbol INDEX::A.
> 
>> Now, at the REPL, if I attempt an action on the closure, it doesn't
>> work as expected.  An example session:
>>
>> CL-USER> (load "indexer.lisp")
>> T
>> CL-USER> (setf (symbol-function 'test) (indexer:init "indexer.conf"))
>> #<FUNCTION (LAMBDA (INDEXER::ACTION)) {ACF116D}>
>> CL-USER> (test 'a)
>> "Unknown action."
>> CL-USER>
>>
>> I'm new at this, so any insight as to what I'm doing incorrectly would
>> be most appreciated.  Thanks for your time.
> 
> In the package CL-USER (mind the prompt!), when you read (test 'a),
> the symbol named "A" is  interned in the package CL-USER.  Therefore
> you are giving to TEST the symbol CL-USER::A.
> 
> Now, let's see the rules for CL:EQUAL...
> 
> Symbols, Numbers, and Characters
>   
>    equal is true of two objects if they are symbols that are eq, if
>    they are numbers that are eql, or if they are characters that are
>    eql.
>   
> CL:EQUAL applied on two symbols is identical to CL:EQ.  Since you
> having imported into CL-USER the symbol INDEXER:A to make both "path"
> refer the same symbol, INDEXER::A and CL-USER::A are distinct, not EQ,
> and not EQUAL.
> 
> 
> So you have two choices:
> 
> - either export the symbols INDEXER:A and INDEXER:B, since obviously
>  they are part of the interface!
> 
> - or test ACTION with STRING-EQUAL, which would allow you to pass any
>  symbol named "A" or "a", or any string containing only the character
>  #\A or #\a.  (or STRING= if you want case sensitivity).
> 
> 
> 
> -- 
> __Pascal Bourguignon__                     http://www.informatimago.com/
> 
> There is no worse tyranny than to force a man to pay for what he does not
> want merely because you think it would be good for him. -- Robert Heinlein

Or, as already mentioned, you can use keywords :a and :b instead which are always interned to the keyword package, so you don't get in trouble with packages.

Andreas
From: ········@gmail.com
Subject: Re: Exported closure issue
Date: 
Message-ID: <1171050059.043123.270990@l53g2000cwa.googlegroups.com>
Thank to everyone for your very insightful responses.  I understand!