Re: How to make GNU Guile more successful

2017-03-06 Thread Arne Babenhauserheide

Alejandro Sanchez writes:

> Thank you for you responses, I will try to respond to them all in one email.
>
>
>> About Emacs + Geiser as the default development environment
> Emacs is a power tool. Giving someone Emacs to write a simple script is like 
> handing someone a jackhammer to nail plywood together. OK, maybe I’m 
> stretching the analogy a bit, but when I think IDE I imagine something that 
> handholds people, for the better or worse. Sure, you could offer some sort of 
> pre-configured Emacs setup, but what’s the point of that?

The point of that is that every developer starts by doing small
things. Therefore the small startup things should work well.

I know many people at work who’ve been using Emacs for years but mostly
limit their use to what it provides by default.

What works well from the start is where most people will stay. And
that’s not unreasonable: If it doesn’t work now, how are the chances
that it will be better than something which works well right away?

>> About the syntax
> I know about wisp, but that looks like an awkward cross-breed between Python 
> and Lisp. Lisp syntax is simply something one needs to get over. For me it 
> really clicked when I understood that Lisp syntax is not really a syntax, 
> it’s the AST (sort of). Wisp reminds me of those people who use the arrow 
> keys Vim and never leave insert-mode, in the end they just have a convoluted 
> Nano. Maybe Wisp will help people, I don’t know, but it didn’t do anything 
> for me.

The difference to vim in insert mode is that wisp provides all features
of scheme. The opening and closing parens just look different :)

(or rather: they are merged into the existing indentation, so this
reduces duplication of information)

>> Closing remark
> The question for someone shopping around for languages is: what is the 
> selling point for Guile (or Scheme)? Being a programmable programming 
> language sounds cool, but what does it let me do? Nothing on Guile's website 
> tells me “look at how easy this is to solve in Guile, you cannot do this in 
> other languages”. What would that be? I don’t know, I’m just a layman. The 
> topic of the thread is “how to make Guile more successful”, and I most of 
> those are technical points, so I’m afraid that discussing popularity is all I 
> can contribute.

You can for example build wisp ;)

And "natural script writing" would have been much harder (and much more
mechanical work) in other languages. In most languages it would have
required parsing the text by hand and explicitly extracting code and
handing it to some function to execute it.

Best wishes,
Arne



Re: The status of JIT compiler of Guile (was: Guile benchmark)

2017-03-06 Thread Nala Ginrut
I've rebased the latest master (2.1.7.1040-0f7db-dirty) and fixed to work.
The result become more interesting with the naive case mentioned in my
earlier mail:
Chez: 15s
Guile-JIT: 12s

Alright, we still need to face some problems.

In Atsuro's original design, there're two files should be included
with Scheme's "include" function  in the compiling time. IMO this is
not a good way, since it'll assume the building path is the same with
source path. Then it complains jit-code-t.scm and
compat-x86_64-linux.scm are missing. I've fixed this issue in Makefile
to make a soft link. In the long term I think it's better to change
its design to use modules.

And we don't have to generate jit-code-t.scm every time we compile.
This file is generated by gen-code-t.scm according to GNU-lightning
header file. Next step, I will move it to script directory and we may
generate it with guild. It's a standalone script actually.

To be continued.



Re: Playing with guile (vs python). Generate file for GDP suitable for gnuplot.

2017-03-06 Thread Thien-Thi Nguyen

() l...@gnu.org (Ludovic Courtès)
() Sat, 11 Feb 2017 15:12:00 +0100

   > (define (file->lines filename)
   >   "Returns a list of lines contained in a file"
   >   (call-with-input-file
   >   filename
   > (lambda (p)
   >   (let loop ([line (read-line p)])
   > (if (eof-object? line) (list)
   > (cons
   >  (substring line 0 (1- (string-length line)))
   >  (loop (read-line p

   UTF-8 I/O is usually faster in Guile 2.0.  You might want to
   make sure your file is opened as UTF-8:

 (with-fluids ((%default-port-encoding "UTF-8"))
   (call-with-input-file file …))

FWIW, we can also use SRFI 13 to save a few cycles:

 (use-modules (ice-9 rdelim) (srfi srfi-13))
 
 (define (file->lines filename)
   "Return a list of lines contained in a file."
   (call-with-input-file
   filename
 (lambda (p)
   (let loop ((acc '()))
 (let ((line (read-line p)))
   (if (eof-object? line)
   (reverse! acc); rv
   (loop (cons (string-drop-right line 1)
   acc

This variant is also more stack-conserving (amenable to TCO),
which should afford some additional speedup.

-- 
Thien-Thi Nguyen ---
 (defun responsep (query)
   (pcase (context query)
 (`(technical ,ml) (correctp ml))
 ...))  748E A0E8 1CB8 A748 9BFA
--- 6CE4 6703 2224 4C80 7502



signature.asc
Description: PGP signature


Re: REPL history

2017-03-06 Thread Vladimir Zhbanov
I probably confused things and my previous post is not correct.

OK, put things other ways. I have a GUI app which starts REPL in
another thread. Is there a way to call a thunk in that REPL from
the GUI app? Basically, I want it to exit gracefully by calling
(quit) in the REPL before GUI exits. 

-- 
  Vladimir



Re: Guile foreign object interface

2017-03-06 Thread Andy Wingo
Hi :)

On Thu 02 Mar 2017 16:47, Mike Gran  writes:

> I wanted to make a quick post about the foreign object interface.
> This is a bit of a placeholder because I haven't had time to
> investigate the interface properly, yet. But I intend to poke at
> it soon.
> But for there record, there are some problematic design patterns
> that I want to make sure can be covered by the new interface.

I am not sure that all cases need to be covered by the new interface to
be able to include it.  I think it would be sufficient to simply replace
SMOBs, unrecommend mark procedures and all that, and get the benefits I
mentioned in my mail.  However that said...

> 1. First off is a Lilypond-like pattern.  A C++ vector
> is used to dynamically add or remove elements.  The memory
> management of those elements lives in the C++ world.  Those elements
> are boxed up as SCM.  GCing the SCM should not free its boxed
> contents, but, deleting the boxed contents from the C++ side
> should render those SCMs invalid in some sense. 

Not really helped by foreign objects AFAIU.

> 2. Mutually owned information. Two structures (A and B) both
> mutually contain a non-GC-malloc'd structure C. C must exist
> so long as one of A or B exist.

Likewise, if I understand A and B to be scheme objects of some kind; the
pattern here would be a gc-managed wrapper around C with a finalizer,
and A and B both use the wrapper.

> 3. Here's one from guile-ncurses. An element ITEM is created with
> some contents. Default memory management suffices: if ITEM is GC'd,
> its contents are GC'd.  But the contents of ITEM can later be
> attached to a COLLECTION. If ITEM is GC'd when attached to
> COLLECTION, its contents are not GC'd.

I understand you mean that ITEM has the only reference on its contents,
and that if it becomes unreachable, the contents also become
unreachable, and may be collected (and possibly finalized if they have a
finalizer and finalizers have a chance to run and all the other
finalizer caveats).  Sure, foreign objects work here, as do any other
Scheme data type, right?  As long as the ITEM finalizer doesn't finalize
its contents.  Each contained object needs its own finalizer I think, if
finalization is necessary.

> 5. Gobject-like subclassing.  In Gtk, an application window is
> a type of a window which is a type of a widget which is a type of
> object. If we were to resurrect an effort on GTK3 binding,
> how would it work for foreign objects?

This is very tricky; there are lots of considerations here.  A new
guile-gobject might well want its own scheme.  However, yes, foreign
objects are subclassable.

Cheers,

Andy



Re: Guile foreign object interface

2017-03-06 Thread Andy Wingo
Hi :)

On Thu 02 Mar 2017 16:47, Mike Gran  writes:

> I wanted to make a quick post about the foreign object interface.
> This is a bit of a placeholder because I haven't had time to
> investigate the interface properly, yet. But I intend to poke at
> it soon.
> But for there record, there are some problematic design patterns
> that I want to make sure can be covered by the new interface.

I am not sure that all cases need to be covered by the new interface to
be able to include it.  I think it would be sufficient to simply replace
SMOBs, unrecommend mark procedures and all that, and get the benefits I
mentioned in my mail.  However that said...

> 1. First off is a Lilypond-like pattern.  A C++ vector
> is used to dynamically add or remove elements.  The memory
> management of those elements lives in the C++ world.  Those elements
> are boxed up as SCM.  GCing the SCM should not free its boxed
> contents, but, deleting the boxed contents from the C++ side
> should render those SCMs invalid in some sense. 

Not really helped by foreign objects AFAIU.

> 2. Mutually owned information. Two structures (A and B) both
> mutually contain a non-GC-malloc'd structure C. C must exist
> so long as one of A or B exist.

Likewise, if I understand A and B to be scheme objects of some kind; the
pattern here would be a gc-managed wrapper around C with a finalizer,
and A and B both use the wrapper.

> 3. Here's one from guile-ncurses. An element ITEM is created with
> some contents. Default memory management suffices: if ITEM is GC'd,
> its contents are GC'd.  But the contents of ITEM can later be
> attached to a COLLECTION. If ITEM is GC'd when attached to
> COLLECTION, its contents are not GC'd.

I understand you mean that ITEM has the only reference on its contents,
and that if it becomes unreachable, the contents also become
unreachable, and may be collected (and possibly finalized if they have a
finalizer and finalizers have a chance to run and all the other
finalizer caveats).  Sure, foreign objects work here, as do any other
Scheme data type, right?  As long as the ITEM finalizer doesn't finalize
its contents.  Each contained object needs its own finalizer I think, if
finalization is necessary.

> 5. Gobject-like subclassing.  In Gtk, an application window is
> a type of a window which is a type of a widget which is a type of
> object. If we were to resurrect an effort on GTK3 binding,
> how would it work for foreign objects?

This is very tricky; there are lots of considerations here.  A new
guile-gobject might well want its own scheme.  However, yes, foreign
objects are subclassable.

Cheers,

Andy



Re: REPL history

2017-03-06 Thread tomas
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On Mon, Mar 06, 2017 at 10:15:02PM +0300, Vladimir Zhbanov wrote:
> I probably confused things and my previous post is not correct.
> 
> OK, put things other ways. I have a GUI app which starts REPL in
> another thread. Is there a way to call a thunk in that REPL from
> the GUI app? Basically, I want it to exit gracefully by calling
> (quit) in the REPL before GUI exits. 

Understood.

Sorry, I fear this is over my head. Hope more knowledgeable folks
chime in :-)

regards
- -- tomás
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.12 (GNU/Linux)

iEYEARECAAYFAli9xrcACgkQBcgs9XrR2kYvzQCfcqpt9ftJ5T5cNTNeBgC6vxtH
i+wAn1t7G93UOvwOhdaCFP+VuW+3agxa
=lIRd
-END PGP SIGNATURE-



Lilypond speed (was Re: How to make GNU Guile more successful)

2017-03-06 Thread Andy Wingo
On Sun 05 Mar 2017 15:01, Thomas Morley  writes:

> Here some timing values
>
> (1)
> lilypond-2.19.52 using guile 1.8.7
> (I would have prefered to build lilypond with a guile-1.8.8 build from
> the guile-repository. Though my try to build it from the
> branch_release-1-8 failed. Instead attempting to fix it, I then used a
> released lilypond-version)
>
> real8m16.191s
> user6m39.864s
> sys0m10.860s
>
> (2)
> guile-2.0.14 build from guile-git-repository, branch remotes/origin/stable-2.0
> lilypond-2.19.56, build from local branch dev/guile-v2.2-work
>
> real34m11.762s
> user45m11.316s
> sys0m5.604s
>
> (3)
> guile-2.1.7 build from guile-git-repository, branch master
> (I've got this warning:
> configure: WARNING: *** GNU Readline is too old on your system.
> configure: WARNING: *** You need readline version 2.1 or later.
> No idea whether this may have an impact on lilyponds compiling-time
> I'll have to test.)
> lilypond-2.19.56, build from local branch dev/guile-v2.2-work
>
> real67m29.132s
> user93m14.812s
> sys0m7.332s

Oh, that's interesting.  IME the only thing that is slower on 2.2
compared to 2.0 is the compiler; everything else is significantly
faster.  Could it be that Lilypond is spending time compiling things
somehow?  Perhaps via scm_load without disabling autocompilation or
something?  Guessing at this point tho.

But that's getting ahead of myself -- do you have a document that
exhibits a similar performance series (1.8 < 2.0 < 2.2) but which
doesn't take so long to run?  That can make perf investigation a bit
more tractable :)

Andy



Re: REPL history

2017-03-06 Thread Andy Wingo
On Mon 06 Mar 2017 20:15, Vladimir Zhbanov  writes:

> OK, put things other ways. I have a GUI app which starts REPL in
> another thread. Is there a way to call a thunk in that REPL from
> the GUI app? Basically, I want it to exit gracefully by calling
> (quit) in the REPL before GUI exits. 

What if, in your GUI app, you call stop-server-and-clients! from (system
repl server) ?  That aborts to a prompt to unwind the stack, so it's not
catchable but a dynamic-wind out guard will run.  Only really works in
2.2 tho I think.

Andy



Re: Playing with guile (vs python). Generate file for GDP suitable for gnuplot.

2017-03-06 Thread Andy Wingo
On Mon 06 Mar 2017 14:50, Thien-Thi Nguyen  writes:

> FWIW, we can also use SRFI 13 to save a few cycles:
>
>  (use-modules (ice-9 rdelim) (srfi srfi-13))
>  
>  (define (file->lines filename)
>"Return a list of lines contained in a file."
>(call-with-input-file
>filename
>  (lambda (p)
>(let loop ((acc '()))
>  (let ((line (read-line p)))
>(if (eof-object? line)
>(reverse! acc); rv
>(loop (cons (string-drop-right line 1)
>acc
>
> This variant is also more stack-conserving (amenable to TCO),
> which should afford some additional speedup.

Interestingly the timings are not dissimilar in 2.2; consider this most
microbenchmarky of cases:

(use-modules (ice-9 match))
(define test (iota #e1e6))
(define (copy-list/accum xs)
  (let lp ((xs xs) (out '()))
(match xs
  ((x . xs) (lp xs (cons x out)))
  (() (reverse! out)
(define (copy-list/recur xs)
  (let lp ((xs xs))
(match xs
  ((x . xs) (cons x (lp xs)))
  (() '()

Doing a ,time (length (copy-list test) at the REPL for both these two
copy-list impls gives me:

 real times (s)

copy-list/recur   |  copy-list/accum

0.067212s   0.046110s
0.077659s   0.059750s
0.065923s   0.040371s
0.066098s   0.062963s
0.062718s   0.040980s

The recursive version is still slower ATM but I think that will go away
once I manage to avoid running the function prelude each time; not
sure.  Anyway, I am happy recommending recursing now :)

Andy



Re: REPL history

2017-03-06 Thread Vladimir Zhbanov
On Mon, Mar 06, 2017 at 09:48:51PM +0100, Andy Wingo wrote:
> On Mon 06 Mar 2017 20:15, Vladimir Zhbanov  writes:
> 
> > OK, put things other ways. I have a GUI app which starts REPL in
> > another thread. Is there a way to call a thunk in that REPL from
> > the GUI app? Basically, I want it to exit gracefully by calling
> > (quit) in the REPL before GUI exits. 
> 
> What if, in your GUI app, you call stop-server-and-clients! from (system
> repl server) ?  That aborts to a prompt to unwind the stack, so it's not
> catchable but a dynamic-wind out guard will run.  Only really works in
> 2.2 tho I think.

Well, I confused things, as I already said, and my first question
was incorrect. Really, I have a procedure something like the following:

(define (my-repl)
  (let ((repl (make-repl (current-language) #f))
(history-filename (make-custom-history-filename)))
(repl-eval repl
   `(begin
  (use-modules (ice-9 session) ; help, apropos and such
   (system repl command)) ; guile meta-commands
  (display "Welcome to my REPL!\n" (current-error-port))
  (resolve-module '(ice-9 readline))
  ;; After resolving that module the variable
  ;; *features* should contain 'readline.
  (if (provided? 'readline)
  (begin
(use-modules (ice-9 readline))
((@ (ice-9 readline) activate-readline))
((@ (ice-9 readline) read-history) ,history-filename))
  (display "Readline is not supported in your 
configuration.\n")
   (current-error-port
(run-repl repl)))

So I don't use repl server here.

What I tried so far is to manually save dynamic state in repl:
  (define ds (current-dynamic-state))

and use it in GUI (with support of guile expression evaluation):
  (with-dynamic-state ds (lambda () (write-history history-filename)))

This is for readline history saving, and works pretty well.

So I was thinking to bake something like this into the above code,
probably by adding a variable on the repl-eval stage to store
initial dynamic state in repl. The problem occured when I started
to call (quit) or (throw 'quit) the same way, that is, in the
thunk called in with-dynamic-state. It just segfaulted.

And my app is tied to 2.0 these days.

-- 
  Vladimir



Re: How to make GNU Guile more successful

2017-03-06 Thread Erik Edrosa
On 03/05/2017 06:57 AM, Jan Wedekind wrote:
> According to Alan Kay's research, the future might be a lot of domain
> specific mini languages. I.e. languages tomorrow are going to be like
> libraries today. Guile supports custom languages which makes it future
> proof at least to some extent.
> 

I think I can see how domain specific mini languages might be the
future. You can look at what has happened in web development to see this
explosion of JavaScript transpilers, hoping to either extend or provide
new ways to design web applications.

> Myself, I am using Scheme because of it's unique metaprogramming
> facilities (Scheme macros) and GNU Guile because it has
> multiple-dispatch object oriented programming (unlike Racket). Also
> Guild's native interface with the Boehm Garbage Collector is quite easy
> to use.
> 
> 
> -- 
> Diese Nachricht wurde von meinem Android-Mobiltelefon mit K-9 Mail
> gesendet.

I started using GNU Guile after reading about rms, emacs, and GNU Guile
where GNU Guile would be used as a similar way to extend software. Then
I fell in love with scheme.



Re: How to make GNU Guile more successful

2017-03-06 Thread Erik Edrosa
On 03/05/2017 09:27 AM, Arne Babenhauserheide wrote:
> 
> Erik Edrosa  writes:
> 
>> I think one issue when you want to compare languages like Python to
>> Scheme is that these languages are dominated by a single
>> implementation.
> 
> I read this argument repeatedly, but it does not apply to C and C++, two
> of the most widely used languages. Therefore that argument might just
> interpret too much into a coincidence — or rather: into a situation
> which happens in the beginning of language development.
> 
> Even Java nowadays has several different implementations.
> 

C, C++, and Java have very large specifications and standards which are
meant to keep the various implementations as compatible as possible.
Although implementations do provide their own extensions and there is
issues between OSes. I agree this argument isn't too strong, but I see
it brought up once in awhile. One issue is it does fracture the
community a bit. If implementations have greater compatibility you see
developers use them in interesting ways. For example in Common Lisp,
I've heard some developers will use CCL in development because it
compiles faster and produces easier to debug code and use SBCL for
building releases because it produces faster code.


>> an awesome application to show off the
>> power of the language, good tooling, and some luck.
> 
> And zealots, never forget zealots. I’d dare to say that people, who
> believe that the language or tool is the best thing in existence and
> give lots of talks about it, are a far too easily underestimated factor
> in the success of any tool.
> 
> Best wishes,
> Arne
> 

I think we have many of those. ;)

- Erik



Re: extension paths

2017-03-06 Thread Thien-Thi Nguyen

() Mike Gran 
() Thu, 26 Jan 2017 22:41:23 + (UTC)

   In ancient days, there were discussions of wrapping
   lt_dladdsearchdir directly, which would provide that
   functionality.  It was actually something that you
   could do in TTN's version of Guile 1.4.

Yeah, that's what ‘lt_dladdsearchdir’ is for.  Here's the code:

/* dynl.c --- dynamic linking */

/* Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2012 Thien-Thi Nguyen
 * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
 *   1998, 1999, 2000, 2002 Free Software Foundation, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "libguile/_scm.h"
#include  /* for PATH_MAX */
#include   /* for snprintf */
#include  /* for strncmp */
#include 
#include "libguile/smob.h"
#include "libguile/ports.h"
#include "libguile/strings.h"
#include "libguile/validate.h"
#include "libltdl/ltdl.h"


typedef void (*cthunk_t) (void);
typedef int (*mainish_func_t) (int argc, char **argv);

static int tc;

#define DYNL_FILENAME(x)(SCM_CELL_OBJECT_1 (x))
#define DYNL_HANDLE(x)  ((lt_dlhandle) SCM_CELL_WORD_2 (x))
#define SET_DYNL_HANDLE(x, v)   (SCM_SET_CELL_WORD_2 ((x), (v)))

static lt_dlhandle
validate_live_dobj (const char * const FUNC_NAME, int pos, SCM obj)
{
  SMOBV (tc, (pos), (obj));
  if (! DYNL_HANDLE (obj))
SCM_MISC_ERROR ("Already unlinked: ~S", SCM_LIST1 (obj));
  return DYNL_HANDLE (obj);
}

#define VALIDATE_LIVE_DOBJ_COPY(pos, obj, cvar) \
  cvar = validate_live_dobj (FUNC_NAME, pos, obj)

static SCM
mark_dynl_obj (SCM ptr)
{
  return DYNL_FILENAME (ptr);
}

static int
print_dynl_obj (SCM exp, SCM port, PSTATE_SNUBBED pstate)
{
  char buf[32 + PATH_MAX];
  SCM filename = DYNL_FILENAME (exp);

  scm_lfwrite (buf, snprintf (buf, sizeof (buf),
  "#",
  (SCM_ROSTRINGP (filename)
   ? SCM_ROCHARS (filename)
   : ""),
  (DYNL_HANDLE (exp)
   ? ""
   : " (unlinked)")),
   port);
  return 1;
}

/* These functions are called with deferred interrupts.  When they want
   to throw errors, they are expected to insert a enable interrupts before
   doing the throw.  It might work to throw an error while interrupts
   are deferred (because they will be unconditionally allowed the next
   time INTSOK is executed, NOINTS and INTSOK do not nest).  */
static void
hopefully (const char * const FUNC_NAME, bool result)
{
  if (!result)
{
  INTSOK ();
  SCM_MISC_ERROR (lt_dlerror (), SCM_EOL);
}
}

#define HOPEFULLY(expression)   hopefully (FUNC_NAME, (expression))
#define ZHOPEFULLY(expression)  HOPEFULLY (! (expression))

DSOPRIVATE void *
scm_i_lt_dlsym (SCM dobj, const char *name)
{
#define FUNC_NAME __func__
  lt_dlhandle handle;

  VALIDATE_LIVE_DOBJ_COPY (1, dobj, handle);
  return lt_dlsym (handle, name);
#undef FUNC_NAME
}

SCM_DEFINE
(scm_dynamic_link, "dynamic-link", 1, 0, 0,
 (SCM name),
 doc: /***
Open the dynamic library file @var{name} and return
its @dfn{library handle}, suitable for passing to the
following functions.
As a special case, if @var{name} is @code{#f},
the returned handle is for the Guile executable itself.  */)
{
#define FUNC_NAME s_scm_dynamic_link
  const char *fname = NULL;
  lt_dladvise advise;
  lt_dlhandle handle;

  if (SCM_NFALSEP (name))
{
  SCM_COERCE_SUBSTR (name);
  SCM_VALIDATE_ROSTRING_COPY (1, name, fname);
}

  NOINTS ();

  ZHOPEFULLY (lt_dladvise_init (&advise));
  ZHOPEFULLY (lt_dladvise_global (&advise));

  if (!fname || '/' != fname[0])
ZHOPEFULLY (lt_dladvise_ext (&advise));

  handle = lt_dlopenadvise (fname, advise);
  lt_dladvise_destroy (&advise);

  HOPEFULLY (handle);

  INTSOK ();
  SCM_RETURN_NEWSMOB2 (tc, SCM_UNPACK (name), handle);
#undef FUNC_NAME
}

SCM_DEFINE
(scm_dynamic_object_p, "dynamic-object?", 1, 0, 0,
 (SCM obj),
 doc: /***
Return @code{#t} iff @var{obj} is a dynamic library handle.  */)
{
  return SCM_BOOL (SCM_SMOB_PREDICATE (tc, obj));
}

SCM_DEFINE
(scm_dynamic_unlink, "dynamic-unlink", 1, 0, 0,
 (SCM h),
 doc: /***
Unlink the library represented b