• Re: lisp-sound v0.2.1

    From Madhu@21:1/5 to All on Sun Feb 16 06:17:06 2025
    * zara <m2tt8wv3gm.fsf@freecol.be> :
    Wrote on Fri, 14 Feb 2025 18:30:33 +0100:


    You didn't run it, but it does not just compile in clisp (2019),
    it works. SFY.

    No it is still wrong and it will also fail with Clisp (if clisp does
    ansi). it'll fail if you load another file with the same functionn
    names.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From zara@21:1/5 to Madhu on Sun Feb 16 05:23:30 2025
    Madhu <enometh@meer.net> writes:

    * zara <m2tt8wv3gm.fsf@freecol.be> :
    Wrote on Fri, 14 Feb 2025 18:30:33 +0100:


    You didn't run it, but it does not just compile in clisp (2019),
    it works. SFY.

    No it is still wrong and it will also fail with Clisp (if clisp does
    ansi). it'll fail if you load another file with the same functionn
    names.

    I ran clisp on NetBSD 10.0 and changed "add" to 'add (See the
    dictionary.lisp file below and run it if you please) :

    Welcome to GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>

    Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
    Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
    Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
    Copyright (c) Bruno Haible, Sam Steingold 1999-2000
    Copyright (c) Sam Steingold, Bruno Haible 2001-2010

    Type :h and hit Enter for context help.

    (load "./dictionary.lisp")
    ;; Loading file ./dictionary.lisp ...
    (0 255)
    ;; Loaded file ./dictionary.lisp
    T


    Bye.

    ;; Here's the working dictionary.lisp file :
    ;;
    ;; -- start of file --
    ;;
    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))

    (defun get-with-index (index)
    (let ((*index 0))
    (loop for el in *dict
    do (if (= (car el) index)
    (return (cadr el))
    (setq *index (+ 1 *index)))
    (return ()))))

    (defun dispatch (msg)
    (cond ((eq msg 'add) #'add)
    ((eq msg 'get-with-index) #'get-with-index)
    (T (print "make-dictionary : Message not understood"))
    ))

    #'dispatch))

    ;; tests
    (setf dictionary (make-dictionary))
    (print (funcall (funcall dictionary 'add) 255))
    ;;
    ;; -- end of file --
    ;;

    zara
    --
    My software & art company : http://ko-fi.com/brandywine9

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Madhu@21:1/5 to All on Sun Feb 16 10:47:51 2025
    * zara <m2pljiv7p9.fsf@freecol.be> :
    Wrote on Sun, 16 Feb 2025 05:23:30 +0100:
    Madhu <enometh@meer.net> writes:
    * zara <m2tt8wv3gm.fsf@freecol.be> :
    Wrote on Fri, 14 Feb 2025 18:30:33 +0100:
    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))

    (defun get-with-index (index)
    (let ((*index 0))
    (loop for el in *dict
    do (if (= (car el) index)
    (return (cadr el))
    (setq *index (+ 1 *index)))
    (return ()))))

    (defun dispatch (msg)
    (cond ((eq msg 'add) #'add)
    ((eq msg 'get-with-index) #'get-with-index)
    (T (print "make-dictionary : Message not understood"))
    ))

    #'dispatch))


    This is still completely wrong and you havent understood it even after
    it has been explained 4 times. You CANNOT use DEFUN here to define
    add. You HAVE to use LABLES instead of defun.

    try loading wavesample.lisp and run the dictionary test again. do you

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From zara@21:1/5 to All on Mon Feb 10 06:30:37 2025
    Hi,

    just wanted to post the start of lisp-sound, there's a neat trick inside using actors without CLOS, see the file dictionary.lisp for an example.

    The code is here :
    http://sf.net/projects/lisp-sound

    Zara
    --
    My software and art company : http://ko-fi.com/brandywine9

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to zara on Mon Feb 17 01:01:57 2025
    On 2025-02-14, zara <johan@freecol.be> wrote:
    Hi,

    Kaz Kylheku <643-408-1753@kylheku.com> writes:

    On 2025-02-14, zara <johan@freecol.be> wrote:

    Here's the example of the dictionary actor without CLOS :

    Your approach has a giant bug, which is fixable.

    ;;
    ;; -- start of file --
    ;;
    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))

    These defuns are defining and later redefining global function
    bindings.


    I know dynamic binding but using the actor there is little error.
    Block scoping using the #'dispatch should almost always call
    the defined add, get-with-index methods etc. not something
    from environments above the lexical scope.

    I can't make heads or tails of this paragraph, but it sounds as if you
    might be trying to convince me that your little coding tidbit isn't
    incorrect. Are /you/ even convinced?

    Make a test case which makes two dictionaries:

    (let ((dict1 (make-dictionary))
    (dict2 (make-dictionary)))
    ...)

    In the ... part, write some tests which show that an operation on
    dict1 has no effect on a lookup in dict1.

    (I mean if you call a message from dispatch, you better define
    your called method locally).

    That's the thing; you've not defined anything locally other
    than the dict* variable.

    defun is not a form which has a local effect.

    I know, but it was just an example. AFAIK I am correct, and you have a
    new Actor system for Common Lisp (e.g. bare bones systems).

    In AFAIK, what exactly do you mean by K, know?

    You are not correct, therefore if you "know" you are correct, there is something wrong with how you determine when you know something
    and when you don't.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From zara@21:1/5 to Kaz Kylheku on Mon Feb 17 09:55:15 2025
    Hi,

    Kaz Kylheku <643-408-1753@kylheku.com> writes:

    On 2025-02-14, zara <johan@freecol.be> wrote:
    Hi,

    Kaz Kylheku <643-408-1753@kylheku.com> writes:

    On 2025-02-14, zara <johan@freecol.be> wrote:

    Here's the example of the dictionary actor without CLOS :

    Your approach has a giant bug, which is fixable.

    ;;
    ;; -- start of file --
    ;;
    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value)))) >>>
    These defuns are defining and later redefining global function
    bindings.


    I know dynamic binding but using the actor there is little error.
    Block scoping using the #'dispatch should almost always call
    the defined add, get-with-index methods etc. not something
    from environments above the lexical scope.

    I can't make heads or tails of this paragraph, but it sounds as if you
    might be trying to convince me that your little coding tidbit isn't incorrect. Are /you/ even convinced?

    Make a test case which makes two dictionaries:

    (let ((dict1 (make-dictionary))
    (dict2 (make-dictionary)))
    ...)

    In the ... part, write some tests which show that an operation on
    dict1 has no effect on a lookup in dict1.


    Every time you do make-dictionary it updates its local *dict. You do not
    call anything dynamic binded, the meaning is to have a method you call
    in an actor class instance, which is block scoped (OOP class and actor).
    If you do not field the message the actor has it not but it is a feature of
    the Lisp language not of my OOP Lisp.

    (I mean if you call a message from dispatch, you better define
    your called method locally).

    That's the thing; you've not defined anything locally other
    than the dict* variable.

    defun is not a form which has a local effect.


    That's it, literally.

    I know, but it was just an example. AFAIK I am correct, and you have a
    new Actor system for Common Lisp (e.g. bare bones systems).

    In AFAIK, what exactly do you mean by K, know?


    It used to work on 2019 clisp with a string not just the symbol,
    which is now correct.

    You are not correct, therefore if you "know" you are correct, there is something wrong with how you determine when you know something
    and when you don't.

    See the clisp output.

    zara
    --
    My software & art company : http://ko-fi.com/brandywine9

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to zara on Mon Feb 10 18:57:30 2025
    On 2025-02-10, zara <johan@freecol.be> wrote:
    Hi,

    just wanted to post the start of lisp-sound, there's a neat trick inside using
    actors without CLOS, see the file dictionary.lisp for an example.

    If you want to discuss some piece of code here, it is best to just post
    it here, in-line with your article.

    Usenet articles are archived. External links tend to rot. Years later,
    your archived article will not make any sense to anyone since the links
    will be long gone.

    The code is here :
    http://sf.net/projects/lisp-sound

    It's not 1999; nobody downloads tarballs from sourceforge to look
    at your code.

    If you're going to refer people to code outside of the discussion,
    you need a landing URL which either gives that code directly,
    or presents a simple directory of file names where the
    "dictionary.lisp" you refer to can quickly be found (without searching
    through any subdirectories) and can be viewed with one additional click.
    Bonus points if the code is nicely formatted and syntax colored.

    If you don't see the barriers in the way you present your work, it makes
    you instantly look like someone who lacks situational awareness, which
    is generally a not a good quality for software dev.

    Such a perception is grossly unfair, but unfair perceptions are out
    there whether we like them or not, but we do have a lot of control
    over them.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Madhu@21:1/5 to All on Tue Feb 11 08:07:48 2025
    * Kaz Kylheku <20250210103727.26@kylheku.com> :
    Wrote on Mon, 10 Feb 2025 18:57:30 -0000 (UTC):

    On 2025-02-10, zara <johan@freecol.be> wrote:
    Hi,
    just wanted to post the start of lisp-sound, there's a neat trick inside using
    actors without CLOS, see the file dictionary.lisp for an example.

    If you want to discuss some piece of code here, it is best to just post
    it here, in-line with your article.

    The code is here :
    http://sf.net/projects/lisp-sound

    It's not 1999; nobody downloads tarballs from sourceforge to look
    at your code.

    wget still works if you tack on &viasf=1 to the query part of the
    download url.

    in this case to master.dl.sourceforge.net/project/lisp-sound/lisp-sound-0.2.1.tar.gz

    I'm currently looking at all lisp audio software, I tried checking this
    out.

    [to the OP]

    The code doenst work, I think it tries to use flavours type dispatch and
    fails on several accounts, it is not common lisp code.

    1. First I added a package file
    package.lisp: (defpackage "LISP-SOUND" (:use "CL"))
    2. and added `(in-package "LISP-SOUND")' forms at the top of all files in
    the directory.
    3. I removed the naked (load "file") forms in some files
    4. I wrote a defsystem

    ```
    (mk:defsystem :lisp-sound
    :source-extension "lisp"
    :components ((:file "package")
    (:module "base"
    :components
    ((:file "channel")
    (:file "dictionary")
    (:file "fs-filter")
    (:file "utilities")
    (:file "16bitsample" :depends-on ("channel"))
    (:file "32bit-multiple-sample" :depends-on ("dictionary"))
    (:file "32bitsample" :depends-on ("channel"))
    (:file "fs" :depends-on ("fs-filter"))
    (:file "wavsample" :depends-on ("32bitsample"))))
    (:module "mixer"
    :components
    ((:file "mix")))
    (:module "sample-enlarger"
    :components
    (:file "32bit-matrix"))))

    To try to compile it.

    Compilation fails, first for syntactic reasons. The parens are not
    balanced in many files.

    there are logic errors, typos, and common lisp errors.

    One example: It tries to use this idiom in dictionary.lisp (after fixing
    typos and paren mismatches)

    ```
    (defun make-dictionary ()
    (let ((*dict ()))
    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))
    (defun get-with-index (index)
    (let ((*index 0))
    (loop for el in *dict
    do (if (= (car el) index)
    (return (cadr el))
    (setq *index (+ 1 *index)))
    (return ()))))
    (defun dispatch (msg)
    (cond ((eq msg 'add) #'add)
    ((eq msg 'get-with-index) #'get-with-index)
    (T (error "make-dictionary : Message not understood ~A" msg))))
    #'dispatch))

    ;(setq $dictionary (make-dictionary))
    ;(print (funcall (funcall $dictionary 'add) 255))
    ```

    But this will flat out fail. You cannot use the a nested defun to deine
    the #'add closure here because defun is global. If you try to (defun
    add) again in another file it will overwrite this definition and you
    will get an infinite loop.

    Instead make-dictionary should use flet labels or labels to do lexical
    binding correctly, say like this:

    ```
    (defun make-dictionary ()
    (let ((*dict ()))
    (labels ((add (value)
    (setq *dict (append *dict (list (length *dict) value))))
    (get-with-index (index)
    (let ((*index 0))
    (loop for el in *dict
    do (if (= (car el) index)
    (return (cadr el))
    (setq *index (+ 1 *index)))
    (return ()))))
    (dispatch (msg)
    (cond ((eq msg 'add) #'add)
    ((eq msg 'get-with-index) #'get-with-index)
    (T (error "make-dictionary: Message not understood ~A" msg)))))
    #'dispatch)))
    ```


    All the code using this pattern has to be updated. I stopped at this
    point for now.

    A git repo of the code (even in sf) would also be helpful in
    communicating the changes back to you.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to zara on Mon Feb 17 16:46:53 2025
    On 2025-02-17, zara <johan@freecol.be> wrote:
    Every time you do make-dictionary it updates its local *dict. You do not

    Every trime you call make-dictionary it redefines a bunch of defuns
    that are contained in the function. Their bodies are lambdas, which
    capture the current lexical dict* variable, but the functions are global.
    Every make-dictionary call you have ever made now uses those new
    functions, which refer to the latest dict* variable and not their
    original one!

    Effectively, your code:

    - wipes the dictionary every time the make-dictionary constructor is called.

    - has all lambdas returned by make-dictionary working with the same
    dictionary object.

    This is the last post in which I'm going to explain it, or reply to
    this topic.

    You are not correct, therefore if you "know" you are correct, there is
    something wrong with how you determine when you know something
    and when you don't.

    See the clisp output.

    What CLISP output? Your only two "test cases" are commented out
    by a semicolon?

    Here is a real CLISP interaction with your code:

    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))

    (defun get-with-index (index)
    (let ((*index 0))
    (loop for el in *dict
    do (if (= (car el) index)
    (return (cadr el))
    (setq *index (+ 1 *index)))
    (return ()))))

    (defun dispatch (msg)
    (cond ((eq msg 'add) #'add)
    ((eq msg 'get-with-index) #'get-with-index)
    (T (print "make-dictionary : Message not understood"))))

    #'dispatch))
    MAKE-DICTIONARY
    (defvar d0 (make-dictionary))
    D0
    (funcall (funcall d0 'add) 'apple)
    (0 APPLE)
    (funcall (funcall d0 'add) 'banana)
    (0 APPLE 2 BANANA)
    (funcall (funcall d0 'add) 'orange)
    (0 APPLE 2 BANANA 4 ORANGE)
    (defvar d1 (make-dictionary)) ;; make new dict, continue with d0
    D1
    (funcall (funcall d0 'add) 'peach)
    (0 PEACH)

    Oops!

    Do you see how dictionary d0 has suddenly developed amnesia?

    What happened to apple, banana and orange?

    Do you think that a dictionary abstration should lose its data
    when someone creates another instance? And if that's the design, why
    use all these function objects. Why allocate several new lambdas
    in each make-dictionary call, when there is only one dictionary?
    Just define a global variable:

    (defvar *dict* ()) ;; the one and only dict

    (defun dict-add (index) ...) ;; add to dictionary

    Maybe read some books/tutorials. (Try not to close them when you think
    you know something different).

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From zara@21:1/5 to All on Fri Feb 14 14:56:35 2025
    Here's the example of the dictionary actor without CLOS :

    ;;
    ;; -- start of file --
    ;;
    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))

    (defun get-with-index (index)
    (let ((*index 0))
    (loop for el in *dict
    do (if (= (car el) index)
    (return (cadr el))
    (setq *index (+ 1 *index)))
    (return ()))))

    (defun dispatch (msg)
    (cond ((eq msg 'add) #'add)
    ((eq msg 'get-with-index) #'get-with-index)
    (T (print "make-dictionary : Message not understood"))))

    #'dispatch))

    ;; tests
    ;(setf dictionary (make-dictionary))
    ;(print (funcall (funcall dictionary "add") 255))
    ;;
    ;; -- end of file --
    ;;

    I had to change two parens to make it compile.
    The tests ran in clisp in 2019.

    zara
    --
    My software & art company : http://ko-fi.com/brandywine9

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to zara on Fri Feb 14 16:53:38 2025
    On 2025-02-14, zara <johan@freecol.be> wrote:

    Here's the example of the dictionary actor without CLOS :

    Your approach has a giant bug, which is fixable.

    ;;
    ;; -- start of file --
    ;;
    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))

    These defuns are defining and later redefining global function
    bindings.

    That means that each new call to make-dictionary will redefine
    add, get-with-index and dispatch suth that they work with the
    latest *dict object.

    The function bodies are lexical closures; they do capture the
    lexical variale *dict. But the expressions #'dispatch,
    #'add, and #'get-with-index are not captured, lexical references.

    You need

    (let ((*dict ()))
    (labels ((add (value) ...)
    (get-with-index (index) ...)
    (dispatch (msg)
    (case msg
    (add #'add)
    (get-with-index #'get-with-index))
    (t (error "make-dictionary: ...."))))
    #'dispathch))

    (Labels defines lexical functions. So does its sister, flet.
    Functions defined in the same labels block can see each other
    and call each other. Those defined by flet cannot; they see
    only functions outside of the flet.)

    Alternatively, we could use variable bindings, whose values
    are closures created by lambda:

    (let ((*dict ()))
    (let* ((add (lambda (value) ...))
    (get-with-index (lambda (index) ...))
    (dispatch (lambda (msg)
    (case msg
    (add add)
    (get-with-index get-with-index))
    (t (error "make-dictionary: ....")))))
    dispatch))

    It's more verbose with the (lambda ...) but we lose the #'.

    Note how I used (error ...) for the unrecognized message
    case, which signals a condition, and not (print ...).

    printing is amateurish. It does nothing to indicate to the
    caller that something went wrong, only logs a message and
    keeps going. The end user of the application won't even
    see the message if it's a GUI unless they know to peek into
    some certain console window or whatever. If they see it,
    they won't know what to do.

    ;; tests
    ;(setf dictionary (make-dictionary))
    ;(print (funcall (funcall dictionary "add") 255))

    What result are you expecting from this test case?
    The string "add" and symbol add are different objects,
    and so (eq "add" 'add) is false; this will not dispatch
    the add method.

    ;;
    ;; -- end of file --
    ;;

    I had to change two parens to make it compile.
    The tests ran in clisp in 2019.

    You forgot to write a test which shows that operations on one dictionary
    have no effect on the apparent contents of another.

    Also, your dictionary is inefficient; Common Lisp already has
    hash tables.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From zara@21:1/5 to Kaz Kylheku on Fri Feb 14 18:30:33 2025
    Hi,

    Kaz Kylheku <643-408-1753@kylheku.com> writes:

    On 2025-02-14, zara <johan@freecol.be> wrote:

    Here's the example of the dictionary actor without CLOS :

    Your approach has a giant bug, which is fixable.

    ;;
    ;; -- start of file --
    ;;
    (defun make-dictionary ()
    (let ((*dict ()))

    (defun add (value)
    (setq *dict (append *dict (list (length *dict) value))))

    These defuns are defining and later redefining global function
    bindings.


    I know dynamic binding but using the actor there is little error.
    Block scoping using the #'dispatch should almost always call
    the defined add, get-with-index methods etc. not something
    from environments above the lexical scope.
    (I mean if you call a message from dispatch, you better define
    your called method locally).

    You need

    (let ((*dict ()))
    (labels ((add (value) ...)
    (get-with-index (index) ...)
    (dispatch (msg)
    (case msg
    (add #'add)
    (get-with-index #'get-with-index))
    (t (error "make-dictionary: ...."))))
    #'dispathch))

    (Labels defines lexical functions. So does its sister, flet.
    Functions defined in the same labels block can see each other
    and call each other. Those defined by flet cannot; they see
    only functions outside of the flet.)


    I didn't know labels. Thanks.

    Alternatively, we could use variable bindings, whose values
    are closures created by lambda:

    (let ((*dict ()))
    (let* ((add (lambda (value) ...))
    (get-with-index (lambda (index) ...))
    (dispatch (lambda (msg)
    (case msg
    (add add)
    (get-with-index get-with-index))
    (t (error "make-dictionary: ....")))))
    dispatch))

    It's more verbose with the (lambda ...) but we lose the #'.


    You do not call #'add you call add, unless it is undefined.

    Note how I used (error ...) for the unrecognized message
    case, which signals a condition, and not (print ...).

    printing is amateurish. It does nothing to indicate to the
    caller that something went wrong, only logs a message and
    keeps going. The end user of the application won't even
    see the message if it's a GUI unless they know to peek into
    some certain console window or whatever. If they see it,
    they won't know what to do.


    I don't use GUIs all the time.

    ;; tests
    ;(setf dictionary (make-dictionary))
    ;(print (funcall (funcall dictionary "add") 255))

    What result are you expecting from this test case?
    The string "add" and symbol add are different objects,
    and so (eq "add" 'add) is false; this will not dispatch
    the add method.


    You didn't run it, but it does not just compile in clisp (2019),
    it works. SFY.

    ;;
    ;; -- end of file --
    ;;

    I had to change two parens to make it compile.
    The tests ran in clisp in 2019.

    You forgot to write a test which shows that operations on one dictionary
    have no effect on the apparent contents of another.

    Also, your dictionary is inefficient; Common Lisp already has
    hash tables.

    I know, but it was just an example. AFAIK I am correct, and you have a
    new Actor system for Common Lisp (e.g. bare bones systems).

    zara
    --
    My software & art company : http://ko-fi.com/brandywine9

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)