How is Lisp's read-eval-print loop different than Python's? - python

I've encounter a following statement by Richard Stallman:
'When you start a Lisp system, it enters a read-eval-print loop. Most other languages have nothing comparable to read, nothing comparable to eval, and nothing comparable to print. What gaping deficiencies! '
Now, I did very little programming in Lisp, but I've wrote considerable amount of code in Python and recently a little in Erlang. My impression was that these languages also offer read-eval-print loop, but Stallman disagrees (at least about Python):
'I skimmed documentation of Python after people told me it was fundamentally similar to Lisp. My conclusion is that that is not so. When you start Lisp, it does 'read', 'eval', and 'print', all of which are missing in Python.'
Is there really a fundamental technical difference between Lisp's and Python's read-eval-print loops? Can you give examples of things that Lisp REPL makes easy and that are difficult to do in Python?

In support of Stallman's position, Python does not do the same thing as typical Lisp systems in the following areas:
The read function in Lisp reads an S-expression, which represents an arbitrary data structure that can either be treated as data, or evaluated as code. The closest thing in Python reads a single string, which you would have to parse yourself if you want it to mean anything.
The eval function in Lisp can execute any Lisp code. The eval function in Python evaluates only expressions, and needs the exec statement to run statements. But both these work with Python source code represented as text, and you have to jump through a bunch of hoops to "eval" a Python AST.
The print function in Lisp writes out an S-expression in exactly the same form that read accepts. print in Python prints out something defined by the data you're trying to print, which is certainly not always reversible.
Stallman's statement is a bit disingenuous, because clearly Python does have functions named exactly eval and print, but they do something different (and inferior) to what he expects.
In my opinion, Python does have some aspects similar to Lisp, and I can understand why people might have recommended that Stallman look into Python. However, as Paul Graham argues in What Made Lisp Different, any programming language that includes all the capabilities of Lisp, must also be Lisp.

Stallman's point is that not implementing an explicit "reader" makes Python's REPL appear crippled compared to Lisps because it removes a crucial step from the REPL process. Reader is the component that transforms a textual input stream into the memory — think of something like an XML parser built into the language and used for both source code and for data. This is useful not only for writing macros (which would in theory be possible in Python with the ast module), but also for debugging and introspection.
Say you're interested in how the incf special form is implemented. You can test it like this:
[4]> (macroexpand '(incf a))
(SETQ A (+ A 1)) ;
But incf can do much more than incrementing symbol values. What exactly does it do when asked to increment a hash table entry? Let's see:
[2]> (macroexpand '(incf (gethash htable key)))
(LET* ((#:G3069 HTABLE) (#:G3070 KEY) (#:G3071 (+ (GETHASH #:G3069 #:G3070) 1)))
(SYSTEM::PUTHASH #:G3069 #:G3070 #:G3071)) ;
Here we learn that incf calls a system-specific puthash function, which is an implementation detail of this Common Lisp system. Note how the "printer" is making use of features known to the "reader", such as introducing anonymous symbols with the #: syntax, and referring to the same symbols within the scope of the expanded expression. Emulating this kind of inspection in Python would be much more verbose and less accessible.
In addition to the obvious uses at the REPL, experienced Lispers use print and read in the code as a simple and readily available serialization tool, comparable to XML or json. While Python has the str function, equivalent to Lisp's print, it lacks the equivalent of read, the closest equivalent being eval. eval of course conflates two different concepts, parsing and evaluation, which leads to problems like this and solutions like this and is a recurring topic on Python forums. This would not be an issue in Lisp precisely because the reader and the evaluator are cleanly separated.
Finally, advanced features of the reader facility enable the programmer to extend the language in ways that even macros could not otherwise provide. A perfect example of such making hard things possible is the infix package by Mark Kantrowitz, implementing a full-featured infix syntax as a reader macro.

In a Lisp-based system one typically develops the program while it is running from the REPL (read eval print loop). So it integrates a bunch of tools: completion, editor, command-line-interpreter, debugger, ... The default is to have that. Type an expression with an error - you are in another REPL level with some debugging commands enabled. You actually have to do something to get rid of this behavior.
You can have two different meanings of the REPL concept:
the Read Eval Print Loop like in Lisp (or a few other similar languages). It reads programs and data, it evaluates and prints the result data. Python does not work this way. Lisp's REPL allows you to work directly in a meta-programming way, writing code which generates (code), check the expansions, transform actual code, etc.. Lisp has read/eval/print as the top loop. Python has something like readstring/evaluate/printstring as the top-loop.
the Command Line Interface. An interactive shell. See for example for IPython. Compare that to Common Lisp's SLIME.
The default shell of Python in default mode is not really that powerful for interactive use:
Python 2.7.2 (default, Jun 20 2012, 16:23:33)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a+2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>>
You get an error message and that's it.
Compare that to the CLISP REPL:
rjmba:~ joswig$ clisp
i i i i i i i ooooo o ooooooo ooooo ooooo
I I I I I I I 8 8 8 8 8 o 8 8
I \ `+' / I 8 8 8 8 8 8
\ `-+-' / 8 8 8 ooooo 8oooo
`-__|__-' 8 8 8 8 8
| 8 o 8 8 o 8 8
------+------ ooooo 8oooooo ooo8ooo ooooo 8
Welcome to GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>
Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010
Type :h and hit Enter for context help.
[1]> (+ a 2)
*** - SYSTEM::READ-EVAL-PRINT: variable A has no value
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead of A.
STORE-VALUE :R2 Input a new value for A.
ABORT :R3 Abort main loop
Break 1 [2]>
CLISP uses Lisp's condition system to break into a debugger REPL. It presents some restarts. Within the error context, the new REPL provides extended commands.
Let's use the :R1 restart:
Break 1 [2]> :r1
Use instead of A> 2
4
[3]>
Thus you get interactive repair of programs and execution runs...

Python's interactive mode differs from Python's "read code from file" mode in several, small, crucial ways, probably inherent in the textual representation of the language. Python is also not homoiconic, something that makes me call it "interactive mode" rather than "read-eval-print loop". That aside, I'd say that it is more a difference of grade than a difference in kind.
Now, something tahtactually comes close to "difference in kind", in a Python code file, you can easily insert blank lines:
def foo(n):
m = n + 1
return m
If you try to paste the identical code into the interpreter, it will consider the function to be "closed" and complain that you have a naked return statement at the wrong indentation. This does not happen in (Common) Lisp.
Furthermore, there are some rather handy convenience variables in Common Lisp (CL) that are not available (at least as far as I know) in Python. Both CL and Python have "value of last expression" (* in CL, _ in Python), but CL also has ** (value of expression before last) and *** (the value of the one before that) and +, ++ and +++ (the expressions themselves). CL also doesn't distinguish between expressions and statements (in essence, everything is an expression) and all of that does help build a much richer REPL experience.
As I said at the beginning, it is more a difference in grade than difference in kind. But had the gap been only a smidgen wider between them, it would probably be a difference in kind, as well.

Related

Why does the Python console repeat back what input into it?

When I write something into the python console, it repeats back what I write.
Like if I write 1, it displays 1 in output, and if I write True it gives True.
Why is this?
Example:
>>1
1
>>True
True
What actually happens in background?
You're typing into a REPL. It Reads input, Evaluates it, Prints the result, then Loops back and starts again.
You're having it read the number 1, evaluate it (although it's just a number), then print the result of the evaluation (the number). After that it waits for more input to be entered so it can run again.
If you typed a more complicated expression, it would be evaluated as well. 1 + 1 will show 2, and [1] * 5 will show [1, 1, 1, 1, 1] for example.
If you want to think about how this is achieved in terms of code, the most basic implementation of a REPL would be something along the lines of:
while True:
user_input = input(">> ")
result = eval(user_input) # eval evaluates a string as code
print(result)
Code similar to this (although likely far more complicated) is just running in the background.
You're talking about one way to invoke the Python interpreter.
This is a computer program designed to accept Python statements, and to print the evaluated result of each one.
In your examples, your statements are simple expressions that evaluate to pretty much what you typed in.
More complex examples include expressions like 1+1, or function calls.
How this works "in [the] background" is far too large a topic for a Stack Overflow answer, but you could study the Python project's source code if you really wanted to know what kind of programming constructs have been used to produce this computer program.
Short answer:
Jeffrey Elkner in his book says that:
When you type a statement on the command line, Python executes it. The interpreter does not display any results....
An expression is a combination of values, variables, operators, and calls to functions. If you type an expression at the Python prompt, the interpreter evaluates it and displays the result, which is always a value
More details:
You know, what a computer really understands is consecutive zero's and one's.
Your hardware is the one who specifies the format of these one's and zero's.
it is hard for people to know about how to order a hardware to do a task. To solve this problem,high level languages and VHLL(very high-level programming languages) such as Python are created.
How do they solve the problem?
These languages are more similar to human languages. In addition, each of these languages has some tool to convert the code to a machine-readable format! (of course, without this, they were worth nothing)
Actually the tools used to convert a human-readable format to machine-readable format, fall into one of these categories: Interpreters, Compilers, Hybrid approach(used in languages like C# and Java).
Python code is executed using an Interpreter!
So when you type an expression or an statement, in python shell, the interpreter comes and executes the statements and evaluates the expressions in your code!
One final point:
Python docs considers expressions, just as a subset of statements(look at the link).

Transcrypt: How to check for empty list?

This a simple python program which causes an endless loop when compiled with Transcrypt 3.7.5:
stack = [ch for ch in "Hello"]
while stack:
print(stack.pop())
This can be solved by replacing while stack: with while len(stack): but this would only be an unacceptable workaround. Is there any other Transcrypt-related pragma switch to get around it?
Use a pragma to switch on truthyness:
http://www.transcrypt.org/docs/html/special_facilities.html#automatic-conversion-to-truth-value-pragma-tconv-and-pragma-notconv
# __pragma__ ('tconv')
stack = [ch for ch in "Hello"]
while stack:
print(stack.pop())
This will print:
o
l
l
e
H
You can also use the -t or --tconv command line switch, as documented in:
http://www.transcrypt.org/docs/html/installation_use.html#available-command-line-switches
Transcrypt aims at supporting 90% of CPython by default and an additional 9% as options through pragma's and command line switches.
The idea is that compiling with defaults gives you fast and compact code and that some mechanisms that are expensive to support via JavaScript can be activated as options. This e.g. holds for operator overloading.
See also:
http://www.transcrypt.org/docs/html/what_why.html#what-is-transcrypt
and
http://www.transcrypt.org/docs/html/differences_cpython.html
There are fully conformant browser Pythons, e.g. PyPyJS:
https://pypyjs.org/
However a page using this takes a very long time to load, which for our needs was unacceptable as we use this for production in real life projects. In general, if you are going to use this professionally, it's worth while reading the docs. I must say I rarely read any documentation myself, but in this case it pays off.
That's simply a non-conforming Python interpreter if it loops infinitely with the provided code. CPython interpreter will not loop infinitely (test.py contains the code in the question):
PS C:\Users\Matt> python test.py
o
l
l
e
H
PS C:\Users\Matt>
It would be hard to suggest a workaround, since with a non-conforming interpreter all bets are off.
Disclaimer: I don't know much about Transcrypt, but you should probably open a bug report

Python meta-circular evaluator

It's not uncommon for an intro programming class to write a Lisp metacircular evaluator. Has there been any attempt at doing this for Python?
Yes, I know that Lisp's structure and syntax lends itself nicely to a metacircular evaluator, etc etc. Python will most likely be more difficult. I am just curious as to whether such an attempt has been made.
For those who don't know what a meta-circular evaluator is, it is an interpreter which is written in the language to be interpreted. For example: a Lisp interpreter written in Lisp, or in our case, a Python interpreter written in Python. For more information, read this chapter from SICP.
As JBernardo said, PyPy is one. However, PyPy's Python interpreter, the meta-circular evaluator that is, is implemented in a statically typed subset of Python called RPython.
You'll be pleased to know that, as of the 1.5 release, PyPy is fully compliant with the official Python 2.7 specification. Even more so: PyPy nearly always beats Python in performance benchmarks.
For more information see PyPy docs and PyPy extra docs.
I think i wrote one here:
"""
Metacircular Python interpreter with macro feature.
By Cees Timmerman, 14aug13.
"""
import re
re_macros = re.compile("^#define (\S+) ([^\r\n]+)", re.MULTILINE)
def meta_python_exec(code):
# Optional meta feature.
macros = re_macros.findall(code)
code = re_macros.sub("", code)
for m in macros:
code = code.replace(m[0], m[1])
# Run the code.
exec(code)
if __name__ == "__main__":
#code = open("metacircular_overflow.py", "r").read() # Causes a stack overflow in Python 3.2.3, but simply raises "RuntimeError: maximum recursion depth exceeded while calling a Python object" in Python 2.7.3.
code = "#define 1 2\r\nprint(1 + 1)"
meta_python_exec(code)

Is it possible to write one-liners in Python? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
I was going through the code golf question here on Stack Overflow and saw many Perl one-liner solutions.
Is something like that possible in Python?
python -c 'print("Yes.")'
It's possible to write one liners in Python but it's awkward (Python encourages well indented code which is somewhat at odds with the "one-liner" concept). It's a bit easier in Python 3 because print() is a function and not a statement. Here's one:
python -c "fact = lambda x: x * fact(x-1) if x > 1 else 1; print(fact(5))"
Here's how you could write a grep like function (this example prints lines from input containing "foo"):
python -c "for s in __import__('fileinput').input(): __import__('sys').stdout.write(s) if 'foo' in s else None"
I end up wanting to do this fairly often when doing stuff from the shell. It doesn't end up being more compact, and in many cases it's easier to just write a multi-line shell command than to write everything as a lambda. You pretty much can't use any Python statement that ends with a colon. So you end up having to
write any for-like code as a genexp or list comprehension. I Do this anyway for most stuff, but it's annoying to have to import sys and push everything to sys.stdout.writelines in cases where you could otherwise just
for tree in forest:
print tree
write lambdas instead of function definitions. This is often workable and has the useful side effect of forcing you to write very directed functions that really only do one thing. However, it's not particularly convenient, and doesn't work for anything that mutates a value (e.g., dict.update) and then returns some element.
Do not bother doing things properly with context managers
Do not do any exception handling.
Use a dictionary of lambdas instead of any if/else sections.
Use type(name, bases, dict) to declare any classes. This is pretty fun but only works if you happen to be declaring a class whose methods can all be expressed as lambdas.
So for some things it works out but generally it's a big hassle, because you end up having to use a functional style that Python doesn't really support. Most of the time I just write multiline shell commands like
python -c $'
import some_module
for v in some_module.whatever():
print "Whatever: \'{0}\'".format(v)
'
The $' is a bash quoting syntax, an alternative to its '...' and "..." quoting constructs. It's useful, because it works like '...', but let’s you escape contained ' characters with \'. You can also embed newlines, so the above code could also be written as python -c $'import some_module\nfor v in some_module.whatever():\n print "Whatever: \'{0}\'".format(v)'. However, this is something of an acquired taste.
One annoying thing about writing multiline commands in bash is that HOME and END go to the beginning of the command rather than the beginning of the line. There may be a better way to do this, but I usually just scan back and forth by holding down CTRL and the left/right arrow keys. Some Emacs user could probably set me straight here, since that's where bash's normal key bindings come from.
If you want to insert a line break while editing a multiline command, you can do this with ^V-^J. That will put in a line break in such a way that you can still scan back to the previous lines, rather than using the
$ first line of the command
> second line
> third line
setup that you get otherwise, where you can't get back to the previous lines.
The trick with ^V-^J works in IPython too, making it useful for editing class or function definitions. It may also work in the basic Python REPL (probably); I just don't know, because I nearly always use IPython.
In Bourne shell you can use something called heredoc to get around Python's dependency on indents:
python << 'EOF'
> for i in range(3):
> print i
> EOF
0
1
2
A really nice Python one-liner (as in "quite useful"):
python -c 'import SimpleHTTPServer as foo; foo.test()' 23433
It creates an instant basic web server in the current directory. (I was just introduced to this today, and it is very handy.)
Here is my trick to run multiple statements:
[stmt1, stmt2, expr1][2]
if requires lazy evaluation: [lambda(): stmt1; lambda(): stmt2][not not boolExpr]()
exec("if 6 * 9 == int('42', 13):\n\tprint('Yes!')")
With this approach, every Python program can be written as a one-liner :)
Yes, actually it is very common. I use one-liners when I need to write quick code. It just depends on what you want to do. Here is a small line I just used this evening. It is the creation of a Tkinter button in a single line.
a = Button(root, text="Button", command=com1).pack()

Equivalent of python eval in Haskell

There is function in python called eval that takes string input and evaluates it.
>>> x = 1
>>> print eval('x+1')
2
>>> print eval('12 + 32')
44
>>>
What is Haskell equivalent of eval function?
It is true that in Haskell, as in Java or C++ or similar languages, you can call out to the compiler, then dynamically load the code and execute it. However, this is generally heavy weight and almost never why people use eval() in other languages.
People tend to use eval() in a language because given that language's facilities, for certain classes of problem, it is easier to construct a string from the program input that resembles the language itself, rather than parse and evaluate the input directly.
For example, if you want to allow users to enter not just numbers in an input field, but simple arithmetic expressions, in Perl or Python it is going to be much easier to just call eval() on the input than writing a parser for the expression language you want to allow. Unfortunately, this kind of approach, almost always results in a poor user experience overall (compiler error messages weren't meant for non-programmers) and opens security holes. Solving these problems without using eval() generally involves a fair bit of code.
In Haskell, thanks to things like Parsec, it is actually very easy to write a parser and evaluator for these kinds of input problems, and considerably removes the yearning for eval.
It doesn't have an inbuilt eval function. However are some packages on hackage that can do the same sort of thing. (docs). Thanks to #luqui there is also hint.
There is no 'eval' built into the language, though Template Haskell allows compile time evaluation.
For runtime 'eval' -- i.e. runtime metaprogramming -- there are a number of packages on Hackage that essentially import GHC or GHCi, including the old hs-plugins package, and the hint package.
hs-plugins has System.Eval.Haskell.
This question is asked 11 years ago, and now use the package hint we can define eval very easily, following is an example as self-contained script (you still need nix to run it)
#!/usr/bin/env nix-shell
#! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [hint])"
#! nix-shell -i "ghci -ignore-dot-ghci -fdefer-type-errors -XTypeApplications"
{-# LANGUAGE ScopedTypeVariables, TypeApplications, PartialTypeSignatures #-}
import Data.Typeable (Typeable)
import qualified Language.Haskell.Interpreter as Hint
-- DOC: https://www.stackage.org/lts-18.18/package/hint-0.9.0.4
eval :: forall t. Typeable t => String -> IO t
eval s = do
mr <- Hint.runInterpreter $ do
Hint.setImports ["Prelude"]
Hint.interpret s (Hint.as :: t)
case mr of
Left err -> error (show err)
Right r -> pure r
-- * Interpret expressions into values:
e1 = eval #Int "1 + 1 :: Int"
e2 = eval #String "\"hello eval\""
-- * Send values from your compiled program to your interpreted program by interpreting a function:
e3 = do
f <- eval #(Int -> [Int]) "\\x -> [1..x]"
pure (f 5)
There is no eval equivalent, Haskell is a statically compiled language, same as C or C++ which does not have eval neither.
This answer shows a minimal example of using the hint package, but it lacks couple of things:
How to evaluate using bindings like let x = 1 in x + 1.
How to handle exceptions, specifically divide by zero.
Here is a more complete example:
import qualified Control.DeepSeq as DS
import Control.Exception (ArithException (..))
import qualified Control.Exception as Ex
import qualified Control.Monad as M
import qualified Data.Either as E
import qualified Language.Haskell.Interpreter as I
evalExpr :: String -> [(String, Integer)] -> IO (Maybe Integer)
evalExpr expr a = Ex.handle handler $ do
i <- I.runInterpreter $ do
I.setImports ["Prelude"]
-- let var = value works too
let stmts = map (\(var, val) -> var ++ " <- return " ++ show val) a
M.forM_ stmts $ \s -> do
I.runStmt s
I.interpret expr (I.as :: Integer)
-- without force, exception is not caught
(Ex.evaluate . DS.force) (E.either (const Nothing) Just i)
where
handler :: ArithException -> IO (Maybe Integer)
handler DivideByZero = return Nothing
handler ex = error $ show ex

Categories

Resources