[வெள்ளி டிசம்பர் 13, 2024] Visuwesh wrote:

> [...]
> Some caveats:
>
>   1. You need to ensure that all the calc-embedded variables that you
>      use in the formula need to be active and evaluated beforehand.
>   2. The calc-embedded var is considered at last after everything else
>      in org-table-get-constant in the advice.  This would be the best
>      way to go forward.
>
> It would be nice to lift the restrict in (1) but I think it would be
> better to leave it to the user to ensure everything stays updated since
> the user may want to use the old value.  However, ensuring all the vars
> are active and eval-ed would be a royal pain when you're quickly
> evaluating a table formula.
>
> Here's the case I used to test this hack:
>
>     x := 3
>
>     y := 5
>
>     z := 5 x - y => 10
>
>
>     | 1 | 20 |
>
>     #+TBLFM: $2=$z*2

OK, this was not so simple as I thought!  Consider the following
example:

    x := 3

    a := 3 x => 9

    y := 5

    x := 2

    z := 5.2 x - y => 5.4

Update x := 3 and y first.  Then update `a' and `z'.  `z' will be 10.6.
Now update x := 2, and update `z' and `a'.  `z' updates to 5.4 as shown
above but `a' remains 9!  Calc looks for the nearest value of the
variable `x' from the definition of `z'.  The Elisp variable that stores
the var information looks like this:

    (cdar calc-embedded-active)

    ([#<buffer scratch.org> #<buffer *Calculator*> #<marker at 289961 in
           scratch.org> #<marker at 289967 in scratch.org> #<marker at
           289960 in scratch.org> #<marker at 289968 in scratch.org>
           #("x := 3" 0 6 (fontified t)) nil
           (calcFunc-assign (var x var-x) 3) (var x var-x) nil
           (calcFunc-assign (var x var-x) 3) nil nil nil nil]
     [#<buffer scratch.org> #<buffer *Calculator*> #<marker at 289969 in
           scratch.org> #<marker at 289982 in scratch.org> #<marker at
           289968 in scratch.org> #<marker at 289983 in scratch.org>
           #("a := 3 x => 9" 0 13 (fontified t)) nil
           (calcFunc-evalto
            (calcFunc-assign (var a var-a) (* 3 (var x var-x))) 9)
           (var a var-a) (((var x var-x))) 9 nil nil nil nil]
     [#<buffer scratch.org> #<buffer *Calculator*> #<marker at 289984 in
           scratch.org> #<marker at 289990 in scratch.org> #<marker at
           289983 in scratch.org> #<marker at 289991 in scratch.org>
           #("y := 5" 0 6 (fontified t)) nil
           (calcFunc-assign (var y var-y) 5) (var y var-y) nil
           (calcFunc-assign (var y var-y) 5) nil nil nil nil]
     [#<buffer scratch.org> #<buffer *Calculator*> #<marker at 289992 in
           scratch.org> #<marker at 289998 in scratch.org> #<marker at
           289991 in scratch.org> #<marker at 289999 in scratch.org>
           #("x := 2" 0 6 (fontified t)) nil
           (calcFunc-assign (var x var-x) 2) (var x var-x) nil
           (calcFunc-assign (var x var-x) 2) nil nil nil nil]
     [#<buffer scratch.org> #<buffer *Calculator*> #<marker at 290000 in
           scratch.org> #<marker at 290021 in scratch.org> #<marker at
           289999 in scratch.org> #<marker at 290022 in scratch.org>
           "z := 5.2 x - y => 5.4" nil
           (calcFunc-evalto
            (calcFunc-assign (var z var-z)
                     (- (* (float 52 -1) (var x var-x))
                    (var y var-y)))
            (float 54 -1))
           (var z var-z) (((var y var-y)) ((var x var-x)))
           (float 54 -1) nil nil nil nil])

Notice how there are two entries for `x'.  Worse still, change x := 3 to
x := 3.3 and update it.  Evaluating the same expression again now yields
three entries for `x'!

    ([#<buffer scratch.org> #<buffer *Calculator*> #<marker at 289961 in
           scratch.org> #<marker at 289967 in scratch.org> #<marker at
           289960 in scratch.org> #<marker at 289970 in scratch.org>
           #("x := 3" 0 6 (fontified t)) nil
           (calcFunc-assign (var x var-x) 3) (var x var-x) nil
           (calcFunc-assign (var x var-x) 3) nil nil nil nil]
     [#<buffer scratch.org> #<buffer *Calculator*> #<marker at 289961 in
           scratch.org> #<marker at 289969 in scratch.org> #<marker at
           289960 in scratch.org> #<marker at 289970 in scratch.org>
           #("x := 3.3" 0 8 (fontified t)) nil
           (calcFunc-assign (var x var-x) (float 33 -1)) (var x var-x)
           nil (calcFunc-assign (var x var-x) (float 33 -1)) nil nil
           nil nil]
     ...
     ...
     [#<buffer scratch.org> #<buffer *Calculator*> #<marker at 289996 in
           scratch.org> #<marker at 290002 in scratch.org> #<marker at
           289995 in scratch.org> #<marker at 290003 in scratch.org>
           #("x := 2" 0 6 (fontified t)) nil
           (calcFunc-assign (var x var-x) 2) (var x var-x) nil
           (calcFunc-assign (var x var-x) 2) nil nil nil nil]
     ...)

Which begs the question: what should be `x'?

In any case, the code I posted above had a problem with decimals.  The
code still picks the first value of VAR that shows up in the list above.

    (defun vz/calc-embedded-get-var (var)
      "Return the value of active `calc-embedded' VAR in current buffer."
      (let* ((info (cdr (assq (current-buffer) calc-embedded-active)))
             (var-info
              (seq-find
               (lambda (x)
                 ;; 9 is the variable name: (var XXX var-XXX)
                 (eq var (nth 1 (aref x 9))))
               info))
             old-val)
        (when (and info var-info)
          ;; This is called the `old-val' in `calc-embedded-update'.
          ;; This can be nil when the formula isn't evaled I think?
          ;; (aref VAR-INFO 8) is again repeated in 11th slot when the
          ;; variable is simply as assignment.
          (let ((calc-line-numbering))
            ;; For the below trick, see `calc-embedded-update' again.
            (math-format-stack-value
             (list (or (if (and (consp (setq old-val (aref var-info 11)))
                                (eq (car old-val) 'calcFun-assign))
                           (car (last old-val))
                         old-val)
                       ;; 8 is the eval form: (calcFun-evalto ...) or
                       ;; (calcFun-assign ...)
                       (car (last (aref var-info 8))))
                   1 nil))))))

    (define-advice org-table-get-constant (:around (oldfun name) 
vz/consider-calc-embedded-var)
      "Check if NAME is a `calc-embedded' at last."
      (let ((val (funcall oldfun name)))
        (if (equal val "#UNDEFINED_NAME")
            (or (vz/calc-embedded-get-var (intern name))
                val)
          val)))

Reply via email to