Program Tip

Lisp의 read-eval-print 루프는 Python과 어떻게 다릅니 까?

programtip 2020. 12. 4. 20:22
반응형

Lisp의 read-eval-print 루프는 Python과 어떻게 다릅니 까?


Richard Stallman 의 다음 진술을 접했습니다 .

'Lisp 시스템을 시작하면 read-eval-print 루프로 들어갑니다. 대부분의 다른 언어는 읽기에 필적 할만한 것이없고 eval에 필적 할만한 것이 없으며 인쇄에 필적 할만한 것이 없습니다. 얼마나 큰 결점입니까! '

자, 저는 Lisp로 프로그래밍을 거의하지 않았지만 Python으로 상당한 양의 코드를 작성했고 최근에는 Erlang으로 조금 작성했습니다. 내 인상은 이러한 언어가 읽기-평가-인쇄 루프를 제공하지만 Stallman은 동의하지 않는다는 것입니다 (적어도 Python에 대해서는).

``사람들이 파이썬이 근본적으로 Lisp와 비슷하다고 말한 후 저는 파이썬 문서를 훑어 보았습니다. 내 결론은 그렇지 않다는 것입니다. Lisp를 시작하면 'read', 'eval', 'print'를 수행하는데, 모두 Python에서 누락되었습니다. '

Lisp와 Python의 read-eval-print 루프간에 근본적인 기술적 차이가 있습니까? Lisp REPL이 쉽고 파이썬에서하기 어려운 것들의 예를 줄 수 있습니까?


Stallman의 입장을 지원하기 위해 Python은 다음 영역에서 일반적인 Lisp 시스템과 동일한 작업을 수행하지 않습니다.

  • readLisp 함수는 데이터로 처리되거나 코드로 평가 될 수있는 임의의 데이터 구조를 나타내는 S- 표현식을 읽습니다. 파이썬에서 가장 가까운 것은 단일 문자열을 읽는데, 어떤 의미를 가지려면 직접 구문 분석해야합니다.

  • evalLisp 함수는 모든 Lisp 코드를 실행할 수 있습니다. evalPython 함수는 표현식 평가 하며 exec문을 실행 하려면 문이 필요합니다 . 그러나이 두 가지 모두 텍스트로 표시된 Python 소스 코드와 함께 작동하며 Python AST를 "평가"하려면 많은 수고를 거쳐야합니다.

  • printLisp 함수는 read수용 하는 것과 똑같은 형식으로 S- 표현식을 작성합니다 . print파이썬에서는 인쇄하려는 데이터로 정의 된 것을 인쇄합니다. 이는 확실히 항상 되돌릴 수있는 것은 아닙니다.

Stallman의 진술은 명확하게 Python 정확히 evaland 라는 함수를 가지고 print있지만 그가 기대하는 것과는 다른 (그리고 열등한) 작업을 수행 하기 때문에 약간 모호 합니다.

제 생각에 파이썬 Lisp와 비슷한 측면을 가지고 있으며 왜 사람들이 Stallman이 파이썬을 살펴 보도록 권장했는지 이해할 수 있습니다. 그러나 폴 그레이엄은 무엇 메이드 리스프에서 다른 주장 , 리스프의 모든 기능을 포함하는 모든 프로그래밍 언어도 있어야 리스프.


Stallman의 요점은 명시적인 "리더"를 구현하지 않으면 Python의 REPL이 Lisps에 비해 REPL 프로세스에서 중요한 단계를 제거하기 때문에 장애가있는 것처럼 보입니다. Reader는 텍스트 입력 스트림을 메모리로 변환하는 구성 요소입니다. 언어에 내장되고 소스 코드 데이터 모두에 사용되는 XML 파서와 같은 것을 생각해보십시오 . 이것은 (이론적으로 ast모듈 과 함께 파이썬에서 가능할 수있는) 매크로를 작성하는 데 뿐만 아니라 디버깅 및 인트로 스펙 션에도 유용합니다 .

incf특수 양식이 구현 되는 방법에 관심이 있다고 가정 해 보겠습니다 . 다음과 같이 테스트 할 수 있습니다.

[4]> (macroexpand '(incf a))
(SETQ A (+ A 1)) ;

그러나 incf기호 값을 증가시키는 것 이상을 수행 할 수 있습니다. 해시 테이블 항목을 늘리라는 요청을 받았을 때 정확히 무엇을합니까? 보자 :

[2]> (macroexpand '(incf (gethash htable key)))
(LET* ((#:G3069 HTABLE) (#:G3070 KEY) (#:G3071 (+ (GETHASH #:G3069 #:G3070) 1)))
 (SYSTEM::PUTHASH #:G3069 #:G3070 #:G3071)) ;

여기서 우리 는이 Common Lisp 시스템의 구현 세부 사항 인 incf시스템 특정 puthash함수 호출하는 것을 배웁니다 . "프린터"가 #:구문 과 함께 익명 기호를 도입 하고 확장 된 표현식의 범위 내에서 동일한 기호를 참조하는 것과 같이 "독자"에게 알려진 기능을 어떻게 사용하는지 주목하십시오 . 파이썬에서 이런 종류의 검사를 에뮬레이트하는 것은 훨씬 더 장황하고 접근하기 어렵습니다.

REPL에서 분명한 용도 외에도, Lispers 사용 경험 printreadXML 또는 JSON에 비해 간단하고 쉽게 사용할 수 직렬화 도구로 코드에서. 파이썬은 가지고 있지만 str리스프의에 해당 기능을 print, 그것의 상당 부족 read, 가장 가까운 동등한 존재를 eval. eval물론 conflates 두 개의 서로 다른 개념, 분석 및 평가, 리드를 이 같은 문제같은 솔루션 및 파이썬 포럼에서 반복되는 주제입니다. 독자와 평가자가 명확하게 분리되어 있기 때문에 Lisp에서는 문제가되지 않습니다.

마지막으로 판독기 기능의 고급 기능을 통해 프로그래머는 매크로조차 제공 할 수없는 방식으로 언어를 확장 할 수 있습니다. 어려운 일을 가능하게하는 완벽한 예는 Mark Kantrowitz infix패키지 로, 완전한 기능의 중위 구문을 리더 매크로로 구현합니다.


Lisp 기반 시스템에서는 일반적으로 REPL (read eval print loop)에서 실행되는 동안 프로그램을 개발합니다. 따라서 완성, 편집기, 명령 줄 인터프리터, 디버거 등 다양한 도구를 통합합니다. 기본값은이를 사용하는 것입니다. 오류가있는 식을 입력합니다. 일부 디버깅 명령이 활성화 된 다른 REPL 수준에 있습니다. 이 동작을 제거하려면 실제로 뭔가를해야합니다.

REPL 개념의 두 가지 다른 의미를 가질 수 있습니다.

  • Lisp (또는 다른 유사한 언어)에서와 같은 Read Eval Print Loop. 프로그램과 데이터를 읽고 결과 데이터를 평가하고 인쇄합니다. 파이썬은 이런 식으로 작동하지 않습니다. Lisp의 REPL을 사용하면 메타 프로그래밍 방식으로 직접 작업하여 코드를 생성 (코드)하고 확장을 확인하고 실제 코드를 변환하는 등의 작업을 수행 할 수 있습니다. Lisp는 최상위 루프로 읽기 / 평가 / 인쇄 기능이 있습니다. 파이썬에는 top-loop로 readstring / evaluate / printstring과 같은 것이 있습니다.

  • 명령 줄 인터페이스. 대화 형 셸. 예를 들어 IPython을 참조하십시오 . Common Lisp의 SLIME과 비교하십시오 .

기본 모드에서 Python의 기본 셸은 대화 형 사용에 그렇게 강력하지 않습니다.

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
>>> 

오류 메시지가 표시되고 그게 전부입니다.

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.

참고URL : https://stackoverflow.com/questions/12253200/how-is-lisps-read-eval-print-loop-different-than-pythons

반응형