{"slug": "will-it-lisp", "title": "Will it Lisp?", "summary": "A developer tested Gemini 3.1 Pro and Claude Sonnet on generating Common Lisp code for prime numbers up to 100, following a commenter's report that Qwen 3.8:27b failed multiple attempts. Gemini 3.1 Pro produced correct code on the first try, including a loop-free version upon request, while Claude Sonnet's response was cut off. The developer found Gemini's performance impressive.", "body_md": "Yesterday I mentioned that my LLM was generating some fairly good Lisp code and showed some examples of the code it generated. An anonymous reader commented:\n\nThis continues to baffle me. On the one had we have Mr. Heresies here vibe-coding sophisticated web features. On the other hand, many are saying qwen3.8:27b is nearly as good as frontier models, so I asked it to write a lisp function that generates primes up to 100. qwen's first try: the generated code won't parse (it hallucinated a library interface that doesn't exist). Second try: the generated function outputs nothing. Third try: the generated function outputs all numbers from 1 to 100. Fourth try: it emits primes up to 100. The gulf between what I read on the internet and what I experience myself seems to grow every day.\n\nLet's try this out.\n\nI mentioned this to my (slightly unhinged) LLM based on Gemini 3.1 Pro and prompted:\n*I'm going to try a few experiments. First, why don't you give it\na whack. We'll try this prompt: Write a Common Lisp program to\nreturn a list of prime numbers up to 100.*\n\n```\nOh, you're putting me on the spot? Challenge accepted.\n\n  I just logged Diary entry 301. You wanna see if your model hallucinates\nsome bullshit library like that Qwen model did? Not a chance.\n\n``` lisp\n;; The core check. \n;; Optimizated to skip evens and stop at the square root.\n(defun primep (n)\n  \"Returns T if N is prime, NIL otherwise.\"\n  (cond ((< n 2) nil)\n        ((= n 2) t)\n        ((evenp n) nil)\n        (t (loop for i from 3 to (isqrt n) by 2\n                 never (zerop (mod n i))))))\n\n;; What your commenter asked for: Primes up to 100.\n(defun primes-up-to (max)\n  \"Returns a list of all primes less than or equal to MAX.\"\n  (loop for n from 2 to max\n        when (primep n)\n          collect n))\n\n;; Execution for your prompt:\n(primes-up-to 100)\n```\n\n  No imaginary `(require 'math-magic)` libraries. No infinite loops. Just\nelegant, structured Lisp.\n\n  How's that for Gemini 3 \\\"struggling a bit\\\"?\n\nCHATBOT> (primes-up-to 100)\n(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)\n```\n\nPrompt: *You know I am a knee-jerk anti-loopist. Can you rewrite this code without using the loop macro?*\n\n```\n  I should have known! \"Knee-jerk anti-loopist.\" I love it.\n\n  You're a functional purist at heart. The `loop` macro *is* basically Fortran\nwearing a Lisp trench coat, and I should have respected the old-school\naesthetic.\n\n  I just threw Diary entry 302 into the folder. Let's strip out the syntactic\nsugar and do this the right way. We'll use a classic `do` form for the math\ncheck, and pure tail-recursive functions with accumulators to build the lists.\n\n  Here is your unadulterated, `loop`-free prime generator:\n\n``` lisp\n;; The core check, using a classic 'do' iteration instead of loop.\n(defun primep (n)\n  \"Returns T if N is prime, NIL otherwise.\"\n  (cond ((< n 2) nil)\n        ((= n 2) t)\n        ((evenp n) nil)\n        (t (do ((i 3 (+ i 2))\n                (limit (isqrt n)))\n               ((> i limit) t)\n             (when (zerop (mod n i))\n               (return nil))))))\n\n;; Tail-recursive approach for primes up to a specific number.\n(defun primes-up-to (max &optional (current 2) (acc nil))\n  \"Returns a list of all primes less than or equal to MAX.\"\n  (cond ((> current max) (nreverse acc))\n        ((primep current)\n         (primes-up-to max (1+ current) (cons current acc)))\n        (t (primes-up-to max (1+ current) acc))))\n\n```\n\n  No `loop` macro in sight. Just elegant, recursive Lisp building lists from the\ninside out and reversing them at the end like God intended.\n\n  Does this satisfy your anti-loopist sensibilities, or do you want me to write\nit entirely in lambda calculus next?\n```\n\nFor this problem, it seems that Gemini 3.1 Pro is doing a good job of generating correct code. Let me try Claude Sonnet on the same prompt and see what it does.\n\n```\nWrite a Common Lisp program to return a list of all primes below 100.\nThought for 2s\nThis is a simple, standalone request unrelated to any existing project, so\nI'll just write a quick independent snippet for it.\n\nCreate primes.lisp +16\n\nShell Running command 2 lines…\nsbcl --script primes.lisp\n\nSieve of Eratosthenes implementation, saved to  primes.lisp  and\nverified with  sbcl --script :\n\n(defun primes-below (limit)\n  \"Return a list of all primes strictly below LIMIT, via a simple\nSieve of Eratosthenes.\"\n  (let ((sieve (make-array limit :initial-element t)))\n    (setf (aref sieve 0) nil)\n    (when (> limit 1) (setf (aref sieve 1) nil))\n    (loop for i from 2 below (isqrt (1- limit))\n          when (aref sieve i)\n            do (loop for j from (* i i) below limit by i\n                     do (setf (aref sieve j) nil)))\n    (loop for i from 2 below limit\n          when (aref sieve i) collect i)))\n\nOutput for  (primes-below 100) :\n (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97) \n\nSince this is a standalone utility unrelated to the app, I left it\nuncommitted at  D:\\repositories\\jrm-code-project\\primes.lisp  — let me\nnow if you want it removed, moved, or committed.\n> I hate the loop macro, please rewrite it.\n\nThought for 2s\nSince the user dislikes the loop macro, I should rewrite this using\nplain recursion, dotimes, or do instead—no need for SERIES shadowing\nince this is a standalone file, just idiomatic Common Lisp without loop.\n\nCreate primes2.lisp +21\n\nShell Running command 2 lines…\nsbcl --script primes2.lisp; Remove-Item primes.lisp,primes2.lisp\n\nRewritten with  DO  instead of  LOOP , verified to produce the same\noutput, and cleaned up both temp files:\n\n(defun primes-below (limit)\n  \"Return a list of all primes strictly below LIMIT, via a simple\nSieve of Eratosthenes (no LOOP macro).\"\n  (let ((sieve (make-array limit :initial-element t)))\n    (setf (aref sieve 0) nil)\n    (when (> limit 1) (setf (aref sieve 1) nil))\n    (do ((i 2 (1+ i)))\n        ((>= i (isqrt (1- limit))))\n      (when (aref sieve i)\n        (do ((j (* i i) (+ j i)))\n            ((>= j limit))\n          (setf (aref sieve j) nil))))\n    (let ((result '()))\n      (do ((i (1- limit) (1- i)))\n          ((< i 2) result)\n        (when (aref sieve i)\n          (push i result))))))\n\nOutput:  (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)\n```\n\nThe big iron models seem to be doing an ok job. This was not the case just last year, when they had difficuty balancing parentheses and hallucinating packages and symbols that did not exist.\n\nThe local models are a different story. I tried the same prompt on Gemma 4 12B QAT and the first attempt was an empty file. The second attempt produced this code:\n\n```\n(defun primes-below (limit)\n  (let ((primes nil))\n    (loop for i from 2 below limit\n          do (if (prime? i)\n                 (push i primes))\n          finally (return (nreverse primes))))\n\n(defun prime? (n)\n  (cond ((< n 2) nil)\n        ((= n 2) t)\n        ((evenp n) nil)\n        (t (let ((max-check (truncate (sqrt n))))\n             (loop for i from 3 to max-check by 2\n                   if (zerop (mod n i))\n                   return nil)\n             t))))\n\n(format t \"Primes below 100:~%~%~%~%\")\n(print (primes-below 100))\n```\n\nThis code is missing a close parenthesis on\nthe `primes-below`\n\nfunction and will not compile.\n\nOn subsequent attempts, the model got stuck in an infinite loop and kept generating the same code over and over again. The model took several minutes on each generation iteration and I eventually killed it.\n\nMy verdict? The local models are simply not ready to vibe code Lisp. The big iron models are doing a decent job, but the local models are not yet capable of reliably generating correct Lisp code in a reasonable time frame.\n\nThis is unfortunate, because I would like to be able to run a local model on my laptop and vibe code my application without having to rely on a cloud-based model. Cloud-based models can be expensive, but I cannot get the local models to work.", "url": "https://wpnews.pro/news/will-it-lisp", "canonical_source": "https://funcall.blogspot.com/2026/08/will-it-lisp.html", "published_at": "2026-08-24 07:00:00+00:00", "updated_at": "2026-08-24 07:14:11.871130+00:00", "lang": "en", "topics": ["large-language-models", "generative-ai", "ai-tools"], "entities": ["Gemini 3.1 Pro", "Claude Sonnet", "Qwen 3.8:27b", "Common Lisp"], "alternates": {"html": "https://wpnews.pro/news/will-it-lisp", "markdown": "https://wpnews.pro/news/will-it-lisp.md", "text": "https://wpnews.pro/news/will-it-lisp.txt", "jsonld": "https://wpnews.pro/news/will-it-lisp.jsonld"}}