Install with Pen
Pen.el on GitHub https://github.com/semiosis/pen.el/
Pen Tutorial https://mullikine.github.io/posts/pen-el-tutorial/
ilambda Tutorial https://semiosis.github.io/posts/ilambda-tutorial/ Just do this

## 𝑖λ (Imaginary Programming Functions)

### Summary

tl;dr: Imaginary Programming (IP) is where data and knowledge has been substituted for inference by a LM. Therefore, the implementation of an 𝑖λ library will be uniquely tailored to each language.

I design and build an IP library named 𝑖λ.el for emacs. Think of it a bit like a functional programming library in that you will find a set of functions and macros for working in the programming paradigm. The objective here is to create some functions for doing IP in emacs lisp, since emacs lisp has the expressive power to prototype such things, but the ideas contained here can easily be transferred to any other programming language. The results of this little experiment will go straight into my thesis.

𝑖λ project
http://github.com/semiosis/ilambda/
IP thesis
https://github.com/semiosis/imaginary-programming-thesis/blob/master/thesis.org
IP library
http://github.com/semiosis/pen.el/blob/master/src/ilambda.el
Glossaries
Imaginary ProgrammingPen.elPrompt EngineeringEpistemology

imacro (like regular macros) are for generating code. idefun, however, doesnt generate the code but attempts to evaluate a function without code, or if code is supplied then imagine evaluating that code rather than actually evaluating it.

It’s kinda crazy that Im-macros run faster and are more reliable than Im-functions, where the opposite is true in regular programming. That’s because they generate the code which can be reused, adjusted and interactively regenerated, where an Im-function will typically have to query the LM every time you call it.

#### The objective with 𝑖λ.el

The objective here is to create IP functions for programming in emacs lisp exclusively.

It will be extended in the future to do all programming languages, but I intend to make 𝑖λ.el simple and effective for programming in emacs lisp without bloat or over-complication.

### Syntax forms

name input returns depends on basic idea
ieval real expression / NL real value ieval will imagine the evaluation of some code without any other context.
imacro/N name &optional args docstr real function implementation imacro does not evaluate. It merely generates code, but that code is imagined. Like idefun it is variadic.
defimacro name &optional args docstr real function implementation imacro/N Select the appropriate imacro/N form depending on the arity of arguments.
idefun name-sym args &optional code-or-task task-or-code impure imaginary function sym ieval and imacro Run an imagined function on the given arguments and return an imagined result, but create a binding for the function.
ilist NL description real list Generate a list of things. Return a real list.
ilambda / 𝑖λ args code-or-task &optional task-or-code name-sym impure imaginary lambda ieval Imaginarily run an expression on the given arguments and return an imagined result.
iparse a real syntax form / expression a real subform ieval Given a syntax form / expression, will parse a syntax form with natural language. Returns the subform.
itest real predicate expression / NL predicate real t or nil ieval Given a pure imaginary lambda represented by a string, imaginary predicate name or
ifilter real predicate expression / NL predicate, real list real list itest Imaginarily filter a real list with natural language and return a real list. Optionally, enforce cardinality.

#### ieval

ieval will simply evaluate the provided string/sexp as emacs lisp code. You must provide ieval with, firstly, the preceding code, which may be, for example, a function definition or package requires, etc. and, secondly, evaluated expression. Either argument can either be a raw string containing code or a sexp, but the expression will be “one-line-ized” for the prompt.

ieval is used by idefun and ilambda.

prompt function for running the eval.

pf-imagine-evaluating-emacs-lisp/2
http://github.com/semiosis/prompts/blob/master/prompts/imagine-evaluating-emacs-lisp-2.prompt
  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26  task: "imagine evaluating emacs lisp" doc: "Given some elisp return the imagined result" prompt-version: 1 prompt: |+ (message (eval )) --> engine: "OpenAI Codex" temperature: 0.2 max-generated-tokens: 60 top-p: 1.0 cache: on stop-sequences: - "\n" vars: - "code" - "expression" validator: "grep -qv '(:return'" examples: - |- (defun double-number (x) (x * x)) - "(double-number 5)" filter: on completion: off insertion: off

The following is the implementation of ieval.

You may pass either a sexp or a raw string containing code.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  (defmacro ieval (expression &optional code) "Imaginarily evaluate the expression, given the code and return a real result." (let* ((code-str (cond ((stringp code) code) ((listp code) (pps code)))) (expression-str (cond ((stringp expression) expression) ((listp expression) (pp-oneline expression)))) (result (car (pen-single-generation (pf-imagine-evaluating-emacs-lisp/2 code-str expression-str :no-select-result t :select-only-match t))))) (ignore-errors (eval-string result))))
 1 2 3 4  (defun test-ieval-2 () (ieval (double-number 5) "(defun double-number (x)\n (x * x))\n;;Test the double-number function"))

Resulting prompt from test-ieval-2:

 1 2 3 4 5  (defun double-number (x) (x * x)) ;;Test the double-number function (message (eval (double-number 5))) --> 

ieval not only evaluates correctly despite the deliberately incorrect naming of the function (it multiplies rather than doubles), but it returns the value as the correct data type.

 1 2 3 4 5  (defun test-ieval () (ieval (double-number 5) (defun double-number (x) (x * x))))

Expansion of test-ieval.

 1 2 3 4 5 6 7  (let ((result (ieval (defun double-number (x) (x * x)) (double-number 5)))) (list2str (list result (type result))))
 1 2  25 integer

#### ilambda / 𝑖λ

Imaginarily run an expression on the given arguments and return an imagined result.

Here are three ilambda subforms which take different arguments.

ilambda/task is the most terse. Only a NL task description is given.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41  (defmacro ilambda/task (args task &optional name-sym) (let* ((slug (s-replace-regexp "-$" "" (slugify (eval task)))) (fsym (or name-sym (intern slug)))) (lambda ,args (eval ;; imagined by an LM (ieval ;; An function and a function call (,',fsym ,,@args) ,,(concat ";; " task)))))) (defalias '𝑖λ/task 'ilambda/task) (defmacro ilambda/task-code (args task code &optional name-sym) (let* ((slug (s-replace-regexp "-$" "" (slugify (eval task)))) (fsym (or name-sym (intern slug)))) (lambda ,args (eval ;; imagined by an LM (ieval ;; An function and a function call (,',fsym ,,@args) (defun ,',fsym ,',args ,,task ,',code)))))) (defalias '𝑖λ/task-code 'ilambda/task-code) (defmacro ilambda/code (args code &optional name-sym) (let ((fsym (or name-sym 'main))) (lambda ,args (eval ;; imagined by an LM (ieval ;; An function and a function call (,',fsym ,,@args) (defun ,',fsym (,',@args) ,',code)))))) (defalias '𝑖λ/code 'ilambda/code)

Demonstrations

 1 2  (mapcar (ilambda/task (x) "double it") '(12 4))
"(24 8)
"

 1 2 3  (mapcar (ilambda/code (x) (+ x 5)) '(4))
"(9)
"

 1 2 3 4  (mapcar (ilambda/task-code (x) "add five" (+ x 5)) '(8))
"(13)
"


The ilambda macro.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  (defmacro ilambda (args code-or-task &optional task-or-code name-sym) "Define an imaginary lambda (𝑖λ)" (let ((task (if (stringp code-or-task) code-or-task task-or-code)) (code (if (listp code-or-task) code-or-task task-or-code))) (cond ((and code (sor task)) (ilambda/task-code ,args ,task ,code ,name-sym)) ((sor task) (ilambda/task ,args ,task ,name-sym)) ((listp code-or-task) (ilambda/code ,args ,code ,name-sym))))) (defalias '𝑖λ 'ilambda)
 1  (-reduce (𝑖λ (x y) "add x to y") (number-sequence 1 3))
"6"


#### idefun

The idefun creates a binding to an imaginary function. The implementation of the idefun need not be specified in order for code to run.

The new prompt function returned by idefun is provided with arguments and the values of those arguments are taken and placed into a prompt. An implementation may be provided to idefun when defining the prompt function or optionally left out. Unlike an imacro, when the prompt function is evaluated the code is not returned. Rather, the code is evaluted in imaginary space.

In short, the LM will imagine the evaluation of the function as opposed to generate code.

idefun returns a binding to a new prompt function.

Some examples:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  (idefun add-two-numbers) (add-two-numbers 5 8) (idefun add-two-numbers (a b)) (add-two-numbers 5 8) (idefun add-two-numbers (a b) "add a to b") (add-two-numbers 5 8) (idefun sum-of-integers) (sum-of-integers 1 2 3 10 200 3000) (idefun thing-to-hex-color) (idefun add-two-numbers (a b) "add a to b")
 1 2 3  (idefun generate-fib-sequence (n)) (pp-to-string (generate-fib-sequence 5))
 1  (1 1 2 3 5)

With a temperature of 0.0, this will hash to the same thing every time!

Strangely, we can’t call it a ’neural hash’ though.

 1 2 3 4 5  (idefun sha-hash-string (s)) (pen-force ((temperature 0.0)) (sha-hash-string "sugar shane"))
 1  f1d3ff8ec24e91b957c9e55adec407f47b55e3ae
 1 2 3 4 5 6  (idefun neural-hash-string (s) "This calculates a neural hash of the string.") (pen-force ((temperature 0.0)) (neural-hash-string "sugar shane"))

“0x7f8b8f8e”

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  (defmacro idefun (name-sym args &optional code-or-task task-or-code) "Define an imaginary function" (cond ((and (stringp name-sym) (not code-or-task)) (progn (setq code-or-task name-sym) (setq name-sym (intern (s-replace-regexp "-$" "" (slugify (str name-sym))))))) ((and (symbolp name-sym) (not code-or-task)) (setq code-or-task (pen-snc "unsnakecase" (sym2str name-sym))))) (defalias ',name-sym (function ,(eval (ilambda ,args ,code-or-task ,task-or-code ,name-sym))))) (idefun idoubleit (x) "double it")  1  (idoubleit 5) "10"   1 2 3 4 5 6  (idefun distance-between-planets (x y) "distance between planets in astronomical units (AU)") (concat (str (distance-between-planets "saturn" "jupiter")) "\n" (str (distance-between-planets "mercury" "jupiter"))) "\"0.05\\n0.387\""  I have no idea if this data is correct but it seems consistent with itself.  1 2 3 4 5 6  (idefun distance-between-planets (x y) "distance between planets in million miles") (concat (str (distance-between-planets "saturn" "jupiter")) "\n" (str (distance-between-planets "mercury" "jupiter"))) "\"1.2\\n5.791\""  "1.2\n5.791"  Sadly, Codex doesn’t know too much about Scoville food hotness. food Scoville scale Pure capsaicin 16,000,000 SHU Jalapeño 10,000 SHU  1 2 3 4 5 6  (idefun scoville-difference (food-a food-b) "difference between two foods in scoville Heat Units (SHUs)") (concat (str (scoville-difference "Pure capsaicin" "Jalapeño")) "\n" (str (scoville-difference "Chipotle" "Trinidad Scorpion Butch"))) "\"0\\n2\""   1 2 3  (idefun hex-for-colour (colour)) (hex-for-colour "watermelon") "\"0x6f3d9c\""   1 2 3  (idefun hex-for-colour (colour)) (hex-for-colour "snow") "\"ffffff\""  Demo #### imacro An imacro actually imagines the implementation of a function. Components of the imacro should be inferred. An imacro with only a function name should work. Also, an imacro is under the hood a regular macro. This means, that expanding the imacro will infer/generate underlying code.  1 2 3  (defun test-imacro-1 () (interactive) (imacro/1 get-real-component-from-imaginary-number))   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  (defun test-imacro-1 () (interactive) (progn (defun get-real-component-from-imaginary-number (number) "Return the real component of a complex number." (if (numberp number) (if (eq (car number) 'polar) (car (cdr number)) number) (error "Not a complex number: %s" number)))))   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  (defun test-imacro-1 () (interactive) (progn (defun get-real-component-from-imaginary-number (number) "Return the real component of the complex number NUMBER." (if (numberp number) (if (eq (car number) 'polar) (nth 1 number) number) number)))) pf-imagine-an-emacs-function/3 http://github.com/semiosis/prompts/blob/master/prompts/imagine-an-emacs-function-3.prompt   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32  title: imagine an emacs function task: "imagine an emacs lisp function given name, arguments and docstring" doc: "Given a function name, arguments and docstring, return the imagined body of the function" prompt-version: 1 prompt: |+ ;;my-emacs-library.el (defun () "" engine: "OpenAI Codex" temperature: 0.2 max-generated-tokens: 1000 top-p: 1.0 cache: on stop-sequences: - "\n\n" vars: - "name" - "arguments" - "docstring" validator: "chomp | sed -z 's/.*\$$.\$$$/\\1/' | grep -q ')'" examples: - "times" - "x y" - "multiply two numbers and return a number" preprocessors: - "slugify" postprocessor: chomp postpostprocessor: "sed -z \"s/^;;my-emacs-library.el\\\\n\\\\n//\"" filter: on completion: off insertion: off
 1 2 3 4 5 6 7 8  (car (pen-single-generation (pf-imagine-an-emacs-function/3 "times" "x y" "multiply two numbers and return a number" :include-prompt t :no-select-result t)))
 1 2 3  (defun times (x y) "multiply two numbers and return a number" (* x y))

There are 3 different versions of imacro depending on how many arguments are supplied to it.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40  (defmacro imacro/3 (name args docstr) "Does not evaluate. It merely generates code." (let* ((argstr (apply 'cmd (mapcar 'slugify (mapcar 'str args)))) (bodystr (car (pen-single-generation (pf-imagine-an-emacs-function/3 name argstr docstr :include-prompt t :no-select-result t)))) (body (eval-string (concat "'" bodystr)))) (progn ,body))) (defmacro imacro/2 (name args) "Does not evaluate. It merely generates code." (let* ((argstr (apply 'cmd (mapcar 'slugify (mapcar 'str args)))) (bodystr (car (pen-single-generation (pf-imagine-an-emacs-function/2 name argstr :include-prompt t :no-select-result t)))) (body (eval-string (concat "'" bodystr)))) (progn ,body))) (defmacro imacro/1 (name) "Does not evaluate. It merely generates code." (let* ((bodystr (car (pen-single-generation (pf-imagine-an-emacs-function/1 name :include-prompt t :no-select-result t)))) (body (eval-string (concat "'" bodystr)))) (progn ,body)))
 1  (imacro/3 my/itimes (a b c) "multiply three complex numbers")
 1 2 3 4 5  (progn (defun my-times (x y z) "multiply three numbers and return a number" (* x y z)))

imacro expansion demo

 1  (imacro/2 my/subtract (a b c))
 1 2 3 4 5 6 7 8  (progn (defun my-subtract (a b c) "Subtract B from A and return the result." (setq result (+ a (- b c))) result))
 1  (imacro/1 my/subtract)
 1 2 3 4 5  (progn (defun my-subtract (a b) "Subtract A - B." (- a b)))

defimacro

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  (defmacro defimacro (name &rest body) "Define imacro" (cond ((= 0 (length body)) (imacro/1 ,name)) ((= 1 (length body)) (imacro/2 ,name ,(car body))) ((= 2 (length body)) (imacro/3 ,name ,(car body) ,(cadr body)))))

All of the following are valid ways to invoke defimacro.

defimacro selects the right imacro/N function depending on the arity of the arguments.

 1 2 3 4  (defimacro my/subtract) (defimacro my/subtract (a b c)) (defimacro my/itimes (a b c) "multiply three complex numbers")

#### ilist

The easiest of the list of syntax forms I aimed to implement, ilist simply takes a the number of items to generate (n) and a string describing the type of thing to generate (type-of-thing). It will return a real list of such things.

 1 2 3 4 5 6 7 8  (defun ilist (n type-of-thing) (interactive (list (read-string-hist "ilist n: ") (read-string-hist "ilist type-of-thing: "))) (pen-single-generation (pf-list-of/2 (str n) (str type-of-thing) :no-select-result t))) (defun test-ilist () (interactive) (etv (pps (ilist 10 "tennis players"))))

#### ifilter

ifilter takes

Example:

 1  (pps (ifilter "is male" (ilist 10 "tennis players")))
 1  (pps (ifilter (lambda (e) (full-name-p e)) (ilist 10 "tennis players")))

#### itest

 1 2 3 4 5 6 7 8 9  (defmacro itest/m (predicate value) (ieval (my/test ,',value) (defun my/test (x) (apply ,',predicate x)))) (defun itest (predicate value) (eval (itest/m ,predicate ,value)))
  1 2 3 4 5 6 7 8 9 10 11  (defun test-itest-1 () (interactive) (etv (itest '(lambda (l) '(= 5 (length l))) '(a b c d)))) (defun test-itest-2 () (interactive) (etv (itest/m (lambda (l) '(= 4 (length l))) '(a b c d))))

#### Derived functions

• get-backstory

#### itransform

 1 2 3 4  (defun get-backstory () ) (itransform)
 1  (pps (mapcar 'get-backstory (ilist 10 "tennis players"))`

### TODO Pure imaginary syntax forms

name
imaginary comparator