• Re: Macro noob

    From B. Pym@Nobody447095@here-nor-there.org to comp.lang.lisp on Wed Jun 18 09:17:47 2025
    From Newsgroup: comp.lang.lisp

    Frank Buss wrote:

    (defun count-words (string)
    "returns the number of words in a string"
    (loop for char across string
    with count = 0 and in-word = nil
    finally (return count)
    do (if (alphanumericp char)
    (unless in-word
    (setf in-word t)
    (incf count))
    (setf in-word nil))))

    Gauche Scheme:

    (use srfi-13) ;; string-index string-skip
    (use srfi-14) ;; character sets

    (define (count-words str)
    (define p 0) ;; Position.
    (let go ((cnt 0) (inc-a 1) (inc-b 0)
    (f0 string-index) (f1 string-skip))
    (set! p (f0 str char-set:letter+digit p))
    (if p
    (go (+ cnt inc-a) inc-b inc-a f1 f0)
    cnt)))

    gosh> (count-words "hi ?? ho xx23zz")
    3
    gosh> (count-words " !! ")
    0
    gosh> (count-words " ")
    0
    gosh> (count-words " foo---bar ")
    2
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From B. Pym@Nobody447095@here-nor-there.org to comp.lang.lisp on Wed Jun 18 17:56:30 2025
    From Newsgroup: comp.lang.lisp

    B. Pym wrote:

    Frank Buss wrote:

    (defun count-words (string)
    "returns the number of words in a string"
    (loop for char across string
    with count = 0 and in-word = nil
    finally (return count)
    do (if (alphanumericp char)
    (unless in-word
    (setf in-word t)
    (incf count))
    (setf in-word nil))))

    Gauche Scheme:

    (use srfi-13) ;; string-index string-skip
    (use srfi-14) ;; character sets

    (define (count-words str)
    (define p 0) ;; Position.
    (let go ((cnt 0) (inc-a 1) (inc-b 0)
    (f0 string-index) (f1 string-skip))
    (set! p (f0 str char-set:letter+digit p))
    (if p
    (go (+ cnt inc-a) inc-b inc-a f1 f0)
    cnt)))

    gosh> (count-words "hi ?? ho xx23zz")
    3
    gosh> (count-words " !! ")
    0
    gosh> (count-words " ")
    0
    gosh> (count-words " foo---bar ")
    2

    More understanbable.

    (define (count-words str)
    (define p 0) ;; Position.
    (let go ((cnt 0)
    (inc-a 1) ;; Amount to increment cnt when finding alphanumerics.
    (inc-b 0) ;; Amount to increment cnt when skipping alphanumerics.
    (func-a string-index) ;; Function to find an alphanumeric.
    (func-b string-skip)) ;; Function to skip alphanumerics.
    (set! p (func-a str char-set:letter+digit p))
    (if p
    ;; When we recurse, we swap the increments and the
    ;; functions. So if we were finding alphanumerics,
    ;; during the next pass we'll be skipping alphanumerics.
    (go (+ cnt inc-a) inc-b inc-a func-b func-a)
    cnt)))

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Kaz Kylheku@643-408-1753@kylheku.com to comp.lang.lisp on Wed Jun 18 18:54:30 2025
    From Newsgroup: comp.lang.lisp

    On 2025-06-18, B. Pym <Nobody447095@here-nor-there.org> wrote:
    B. Pym wrote:

    Frank Buss wrote:

    (defun count-words (string)
    "returns the number of words in a string"
    (loop for char across string
    with count = 0 and in-word = nil
    finally (return count)
    do (if (alphanumericp char)
    (unless in-word
    (setf in-word t)
    (incf count))
    (setf in-word nil))))

    Gauche Scheme:

    (use srfi-13) ;; string-index string-skip
    (use srfi-14) ;; character sets

    (define (count-words str)
    (define p 0) ;; Position.
    (let go ((cnt 0) (inc-a 1) (inc-b 0)
    (f0 string-index) (f1 string-skip))
    (set! p (f0 str char-set:letter+digit p))
    (if p
    (go (+ cnt inc-a) inc-b inc-a f1 f0)
    cnt)))

    gosh> (count-words "hi ?? ho xx23zz")
    3
    gosh> (count-words " !! ")
    0
    gosh> (count-words " ")
    0
    gosh> (count-words " foo---bar ")
    2

    More understanbable.

    (define (count-words str)
    (define p 0) ;; Position.
    (let go ((cnt 0)
    (inc-a 1) ;; Amount to increment cnt when finding alphanumerics.
    (inc-b 0) ;; Amount to increment cnt when skipping alphanumerics.
    (func-a string-index) ;; Function to find an alphanumeric.
    (func-b string-skip)) ;; Function to skip alphanumerics.
    (set! p (func-a str char-set:letter+digit p))
    (if p
    ;; When we recurse, we swap the increments and the
    ;; functions. So if we were finding alphanumerics,
    ;; during the next pass we'll be skipping alphanumerics.
    (go (+ cnt inc-a) inc-b inc-a func-b func-a)
    cnt)))

    That's longer than Frank Buss' loop and less understandable.
    You've got iteration expressed by tail recursion.
    Sine you have only one tail call in one place, you might
    as well relocate that to the top and have a do loop:

    (do ((cnt 0 (+ cnt inc-a))
    (inc-a 1 inc-b)
    (func-a string-index func-b)
    (func-b string-skip func-a))
    ...)

    You have a loop which swaps two functions on each iteration.
    What's next; continuations?

    Frank's loop code doesn't do any function indirection.
    A programming neophyte can work out what it does.

    Now watch:

    [partition-by chr-isalnum "How, now brow cow!!"]
    ("How" ", " "now" " " "brow" " " "cow" "!!")

    (flow "***How now, brown cow?!"
    (partition-by chr-isalnum))
    ("***" "How" " " "now" ", " "brown" " " "cow" "?!")

    (flow "***How now, brown cow?!"
    (partition-by chr-isalnum)
    (keep-if [chain 0 chr-isalnum]))
    ("How" "now" "brown" "cow")

    (flow "***How now, brown cow?!"
    (partition-by chr-isalnum)
    (keep-if [chain 0 chr-isalnum])
    len)
    4

    Or, just use regex!

    (tok #/[\w\d]+/ "***How now, brown cow?!")
    ("How" "now" "brown" "cow")
    (len (tok #/[\w\d]+/ "***How now, brown cow?!"))
    4
    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    --- Synchronet 3.21d-Linux NewsLink 1.2