PRE-FACE
Avid libre computing and copyleft supporter,
Long year GNU Emacs mainstream user,
just surpassing the point where GNU Emacs becomes play dough,
essentially by starting to learn eLisp.
Before that turned into beginner to intermediate bash script coder—so, in bash I'm familiar with some basic concepts of programming, and now wondering how they look like in eLisp.
STARTING POINT
I have a function.
What it does in simple terms:
Transforming "4" into "4.0", leaving "742.0" as "742.0"—no matter if data type of input is NUMBER or STRING.
Definition:
;; decimalizer and decimalizing-all-integers-no-matter-how-many ;; ;; Copyleft 🄯 2024 ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Affero General Public License as published by ;; the Free Software Foundation, either version 3 of the License, 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 Affero General Public License for more details. ;; ;; You should have received a copy of the GNU Affero General Public License ;; along with this program. If not, see <https://www.gnu.org/licenses/>. ;; 2-part eLisp function ;; Ensuring that arbitrary number of ARGS in form of NUMBER or numerical STRING ;; are decimals, transforming if necessary. ; part 1: decimalizer (defun decimalizer (num-value) "Usage example: Input: NUMBER 4 or 4.0 or STRING 4 or 4.0 Output: NUMBER 4.0" (let ((x num-value)) ; parse 'n process section (cond ((numberp x) x) ((stringp x) (setq x (string-to-number x))) (t (message "Invalid input: Wrong data type - valid are numericals or values transformable into numerical data types.")) ) ; main section (string-to-number (replace-regexp-in-string "[0-9]*$" "\\&.0" (number-to-string x) ) ) ) ) ; part 2: decimalizing-all-integers-no-matter-how-many (defun decimalizing-all-integers-no-matter-how-many (a b c d e f g) (let ((a (decimalizer a)) (b (decimalizer b)) (c (decimalizer c)) (d (decimalizer d)) (e (decimalizer e)) (f (decimalizer f)) (g (decimalizer g))) (insert (number-to-string a)) (newline) (insert (number-to-string b)) (newline) (insert (number-to-string c)) (newline) (insert (number-to-string d)) (newline) (insert (number-to-string e)) (newline) (insert (number-to-string f)) (newline) (insert (number-to-string g)) (newline) ) ) Usage example:
Input:
(decimalizing-all-integers-no-matter-how-many 1 2 4 "8.0" 2 "343" 9) Output:
1.0 2.0 4.0 8.0 2.0 343.0 9.0 CODE EVALUATION of part 2 decimalizing-all-integers-no-matter-how-many
• The variable handling is very repetitive. The code would be far more efficient and easier to understand, if the all the variables would be grouped together in processing. In bash, when you invoke a tool with additional parameters, all these additional parameters automatically are stored in this $ building block—a variable. While coding one can access the first additional parameter by variable"$1", the second by variable "$2", or all at once by variables "$@" or "$*". Building upon that one can insert just 1 single set of tool invocations, like "First take VARIABLE and make sure its a NUMBER, then transform data type to STRING, do regular expression string replacement, and finally transform data type back to NUMBER.", and let the row of variables loop through this one by one, instead of creating that code block x times with just having the variable spot changed from a (1st code block) to b (2nd code block), and so on, as is right now in eLisp edition of the program.
• The number of arguments is fixed, not arbitrary. Number of variables passed to this tool is supposed to don't matter; no matter if
(decimalizing-all-integers-no-matter-how-many 1 2 4 "8.0" 2 "343" 9) or (decimalizing-all-integers-no-matter-how-many 1 2 4 "8.0" 9) or (decimalizing-all-integers-no-matter-how-many 1 2 4 "8.0" 2 "343" 9 324324 8 8498) always all passed variables should be processed as intended
1.0 2.0 4.0 8.0 2.0 343.0 9.0 or 1.0 2.0 4.0 8.0 9.0 or 1.0 2.0 4.0 8.0 2.0 343.0 9.0 324324.0 8.0 8498.0 In bash, that flexible way of handling the number of passed arguments is pretty much built-in, default.
WHAT I'VE TRIED
—all in vain due to lack of skills, so it could be the right direction.
• function dolist
• &rest
• function mapcar
• lambda
• Researching lots of associated documentation and code examples
CHALLENGE
• In given situation, how to simplify code correctly by grouping all arguments together to a list, and how to loop through that list, so that desired output remains?
• In given situation, how to implement argument section, so that it's flexible—instead of requiring a fixed number of arguments as input—so that desired output remains?
elisptag except in the specific situation described in the link.C-h i g(eintr)and start reading.C-h R elisp). There you will find that the number stack in Elisp makes no distinction between4.0and4. That's not to say that there aren't different floating-point and integral number types: there are. It's just that type promotion, demotion and coercion happen transparently. Once it's a number it's a number. In other words, there is no point in massaging a string representing"4"into one representing"4.0"prior to conversion usingstring-to-number.formatfunction. It's basically a port of the Cprintffunction to Elisp. I think that might be sufficient to replace your currentreplace-regexp-in-stringcall.(let ((x 4)) (/ 6 x)) => 1whereas(let ((x 4)) (/ 6 (float x))) => 1.5. This is because integer-only division (calleddivin some languages) is sometimes what you want.