Revisiting the Android, UserLAnd app.

One of the facts which I had reported some time ago was, that a handy, easy-to-use Android app exists, which is called ‘UserLAnd‘, and, that I had installed it on my Google Pixel C Tablet. As the tooltip suggests, this is an Android app that will allow people to install a basic Linux system, without requiring ‘root’. Therefore, it mounts the apparent, local Linux file system with ‘proot’ – which is similar in how it works to ‘chroot’, except that ‘proot’ does not require root by the host system to set up – and any attempts to obtain root within this Linux system really fail to change the userid, of the app that the files belong to, or of the processes running. Yet, becoming root within this sandboxed version of Linux will convince Linux, for the purpose of installing or removing packages via ‘apt-get’.

In the meantime, I have uninstalled the ‘UserLAnd’ Linux guest system from my Pixel C Tablet, in order to free up storage. But, I have set up something like this again, on my Samsung Galaxy Tab S6 Tablet, which has 256GB of internal storage. Therefore, I have a few observations to add, about how this app runs under Android 10.

Through no fault of the developer of this Android app, the user is more restricted in what he can run, because Android 10 places new restrictions on regular processes. Specifically, none of the major LISP Interpreters that were designed to run under Debian 10 / Buster will run. (:1) What the Linux developers did was, to make the garbage collection of their LISP Interpreters more aggressive, through a strategy that changes the memory protection bits of memory-maps, to read-only if they belong to the state of the machine, and then, ~to try deleting as much of the bytecode as can still be deleted~. Pardon me, if my oversimplification gets some of it wrong.

Well, Android 10 no longer allows regular apps to change the protected memory state of any pages of RAM, for which reason none of the affected LISP Interpreters will run. And for that reason, neither “Maxima” nor anything that depends on Maxima can be made to run.

Yet, certain other Linux applications, notably “LibreOffice” and “Inkscape”, run just fine… So does “GIMP”…

Screenshot_20200912-171020_VNC Viewer

Also, the way in which files can be shared between theĀ  Android Host and the Linux Guest System has been changed, as the following two screen-shots show:

Screenshot_20200912-155032_VNC Viewer

Screenshot_20200912-155144_File Manager

Here, the file ‘Text-File.txt’ has been shared between Android and Linux. Larger files can also be shared in the same way, and the folder bookmarked under Linux. (:2)

In many ways, the Linux applications behave as described before, with the unfortunate exceptions I just named, and I intend to keep using this app.

Technically, a Host app that just sandboxes a Guest Application in this way, does not count as a Virtual Machine. A real VM allows processes to obtain root within the Guest System, without endangering the Host System. Also, ‘a real VM’ provides binary emulation, that makes no specific assumptions about the Guest System, other than, usually, what CPU is being used. Emulation that includes non-native CPU emulation is still a somewhat special type of emulation.

Therefore, the ability of Debian 10 / Buster to run under ‘UserLAnd’ depends, in this case, on the Linux package maintainers having cross-compiled the packages, to run on an ‘ARM-64′ CPU…

 

(Updated 9/13/2020, 21h30… )

Continue reading Revisiting the Android, UserLAnd app.

A LISP function that expands macros fully: macroexpand-all .

This posting will assume that the reader is sufficiently familiar with LISP, to understand how its macros generally work. What such readers will often want to do, is to be able to expand macros, mainly for debugging purposes, before they get compiled into a function. This is because of the fact that, with many LISP implementations, functions are generally compiled in such a way, given actual LISP that acted as source code, and which the macro partially built, that the functions cannot be decompiled, nor the original LISP code recovered from them.

What Common LISP offers, are the functions ‘MACROEXPAND’ and ‘MACROEXPAND-1′, the first of which depends on the second. But, As the Common LISP Hyperspec already points out, ‘MACROEXPAND’ will only keep calling ‘MACROEXPAND-1′, until the second output from this subservient function returns as Nil. This will happen, when the argument is no longer a Macro Form. But, as is already mentioned, this second value output by the subservient function will return as Nil, even if the LISP expression still contains Macro Sub-Forms. And the reason this behaviour can be problematic is the fact that most LISP compilers will keep expanding the Macro Sub-Forms as well, when a macro has been put into a function. This is actually, what makes recursive macros fully possible.

And so, as a better debugging tool, what some LISP programmers might need, is a function that expands all the Macro Sub-Forms as well (even before the macro has been used in a function definition). The following LISP Function accomplishes this:

 


(defun macroexpand-lists (input)
    (cond ((null (listp input)) input)
        ((null input) NIL)
        ((listp (car input)) (cons (macroexpand-all (car input))
                (macroexpand-lists (cdr input)) ) )
        (T (cons (car input) (macroexpand-lists (cdr input)) ) ) ) )

(defun macroexpand-all (input)
    (cond ((null (listp input)) input)
        ((null input) NIL)
        (T
            (let ((expansion1 (macroexpand input)))
                (cond ((null (listp expansion1)) expansion1)
                    ((eq (car expansion1) 'cl:function) expansion1)
                    ((listp (car expansion1))
                        (macroexpand-lists expansion1) )
                    (T (cons (car expansion1)
                                (macroexpand-lists (cdr expansion1)) ) ) ) ) ) ) )

 

Now, I suppose that what the reader may want to see next could be, how this function of mine performs, if I feed it a LISP Macro, Which I defined in an earlier posting. And the following snip illustrates this. The following snip assumes that the Macro, its subservient Function, and the Macro-Expansion Function were already loaded into a LISP session, as that session was started…

(Updated 7/20/2020, 15h05,,, )

Continue reading A LISP function that expands macros fully: macroexpand-all .

An idiosyncrasy, in how Maxima evaluates parameters.

One of the facts which I had written about Maxima in an earlier posting was, that it seems to have a number of functions, the purpose of which in English seemed to be, ‘Take a parameter or expression as input, but give me the value of this parameter.’ And what I had actually written was, that this availability of more than one similar function, could confuse me at one point in time, into not actually knowing what one specific function does. Yet, reflecting on the question outside the exercise that I was doing, brought back the gist of what that function really does. In the previous context, it was the function ‘ev()’.

A context which some other people have noticed instead, is that they’d like to use the Maxima ‘tex()’ function, in order to convert some expression into LaTeX, for another application to typeset, but in some cases the other users wanted to use previous lines of input directly, rather than to use previous lines of output. And what they found was, that the LaTeX version of what they had input, was a ‘verbatim’ block, different according to LaTeX, from what needs to be typeset as Math.

Both issues arise somewhere, because Maxima itself has been programmed in the language LISP. And, most of the time, LISP just seems to produce correct results, according to the way some people tend to interpret the meaning of the LISP function call. But in certain cases, people who either program in, or use LISP, need to form a mental, step-by-step picture of what the LISP interpreter actually does. LISP evaluates both atoms and lists, the latter of which could represent Mathematical expressions, but the former of which represent variables, in situations where their values are being referred to, and not the atom itself. At any point in the computation, LISP will actually evaluate an atom or a list, according to the same semantics. Given an atom, its value is returned, which could be another atom as easily as a list. And, given a list, to return its value means, to execute that list once.

The modern way to refer to what I’ve called an Atom here, is as a “Symbol”, which is really the name of a (LISP) Variable, that also has a value, at a given instant in time.

The way LISP generally defines lists, each of their elements may either be an atom or another list, ‘nested’ within its parent list. In LISP, lists are slightly more common, the first element of which is an atom, just because in such a case, this first element states which function is to be called on the remaining elements. But, in LISP, data is also represented as either a list or an atom, and then, in the case of a list, there is no specific need for the first element to be an atom, or one that represents a defined LISP function. (:1)

Obviously, most other Computing languages, including the one which Maxima interprets, states the function-name first, followed by one set of parentheses, around any argument-list, or around a parameter-list, in the case where the function is being defined. Infix operators are usually also represented internally, as predicates, in whatever data-format those can be represented. One major exception to this takes the form of ‘stack-based languages’, such as ‘FORTH’, and another exception exists in Assembler.

Aside: ‘Prolog’ represents both data and programming as an n-graph, meaning that in this language, each node of a tree may have an arbitrary number of branches, including zero, but additionally, an atomic predicate, stating whichever relationship between the other branches is to be satisfied.

The total number of times LISP evaluates a parameter is tightly defined, so that, if an atom represents a variable, which in turn has a list as its value, that item will result, but not be executed, unless the command is given explicitly, to evaluate the result of the previous evaluation. In LISP, the function which gives such an explicit command, is called ‘EVAL’, and the way to give that instruction, in any context where the variable ‘X’ is instantiated, is like so:

(EVAL X)

Because of the way LISP generally evaluates lists, since ‘X’ does not have a tick – a single quote – in front of it, ‘X’ was already evaluated once, before being passed to ‘EVAL’. And then, ‘EVAL’ evaluates whatever value ‘X’ had, a second time. Even according to Human thought, the fact that ‘X’ represented a value, can seem to disappear, so that Humans will also think, ‘Whatever is being referred to as X, evaluate that.’

Well, the way this works can be revealed, in certain uses of Maxima, such as, if the ‘tex()’ function is being called on an input identifier, when most of the time, it was meant to be used either, on an expression that has been parsed into a LISP structure, or, on a variable, which already evaluated to such an expression, before ‘tex()’ went to work on it.

Yet, because some people want to obtain the LaTeX representation of text, which they previously input, from Maxima, the following text-log displays where an extra step needs to be inserted, in order to accomplish this:

(Updated 7/14/2020, 22h15… )

Continue reading An idiosyncrasy, in how Maxima evaluates parameters.

The Possibility of a Side-Register

The possibility can be considered, that in a certain implementation of LISP, a side-register on the CPU keeps track of what the data-type is, that the main register points to. But as the following experiment shows, this would only help accelerate how LISP expressions are evaluated, and does not affect how Common LISP in particular, stores the data-type in a variable. I.e., on the assumption that the data-type is held in a side-register, we could additionally assume that it gets inserted into the plist of a symbol, whenever we assign the value to the symbol. And what I have shown below, is that this additional assumption would be false, in the case of Common LISP:

Continue reading The Possibility of a Side-Register