Erste Schritte mit Lisp für Pythonista: Ergänzung

Einführung

Dies ist ein ergänzender Artikel zu Einführung in Lisp für Pythonista (Hy tutorial Japanese Translation). In Hy Tutorial war der größte Teil des Inhalts ** "Was Sie in Python schreiben, schreiben Sie dies in Hy" **, aber auch das Es gibt einige Orte, die für den praktischen Gebrauch nicht ausreichen. In diesem Artikel möchte ich eine ergänzende Erklärung der einzigartigen Funktionen von Hy geben, dh der Funktionen von Hy ** und der einzigartigen Funktionen von Hy **, die Python nicht bietet. Wenn Sie dies lesen, reicht es meiner Meinung nach aus, vorerst Hy anstelle von Python zu verwenden.

Ich möchte es zusammen lesen

Ich habe die folgenden guten Artikel außer Qiita gefunden. Bitte beziehen Sie sich auch auf sie. (Vorheriger Beitrag und Moro-Cover, dies ist nützlicher ...)

Schimmel

Es unterstützt Typen ähnlich wie Python. Es gibt jedoch einige Unterschiede zwischen der Python 2.x-Serie und der 3.x-Serie. Das Verhalten ist das gleiche, aber der Typ ist unterschiedlich.

Ganzzahliger Typ

Es ist "lang" in Python 2.x und "int" in der 3.x-Serie.

Ganzzahl in Python2


=> (type 2)
<type 'long'>

Ganzzahl in Python 3


=> (type 2)
<class 'int'>

Zeichenfolgentyp

In Python 2.x ist es "Unicode" und in der 3.x-Serie ist es "str".

Zeichenfolge in Python2


=> (type "a")
<type 'unicode'>

Zeichenfolge in Python 3


=> (type "a")
<class 'str'>

Übrigens ist die Zeichenfolge in doppelte Anführungszeichen (" ) eingeschlossen. Anführungszeichen ( ') sind nicht zulässig. Im Gegensatz zu Python sind auch Unterbrechungen in der Mitte zulässig.

nil Hy ist Lisp, also denke ich nicht, dass es ohne Null anfangen wird. Hy ist jedoch auch Python, sodass es in Bezug auf die Typen eher Python-kompatibel ist. Daher ** gibt es keine Null **. Verwenden Sie je nach Kontext eine leere Liste ([] oder ()), ein leeres Taple ((,)), False, None usw. Wenn Sie ein Pythonista sind, der nicht Lisper ist, können Sie wie zuvor fortfahren.

Arten von Klammern

Wie bei Clojure gibt es im Gegensatz zu anderen Lisps ** einen Unterschied in Klammern **.

(...) Stellt eine Liste dar. Da es sich jedoch um ein etwas anderes Konzept als Pythons "Liste" handelt, werden wir es zur Unterscheidung * Lisp-Liste * nennen. In der * Lisp-Liste * ist das erste Element eine Funktion, und die verbleibenden Elemente werden als Argumente verwendet. Daher entspricht (Funktionswert1 Wert2 ...) der Funktion (* [Wert1, Wert2 ...]) `in Python.

Liste von Lisp


=> (+ 1 2 3)
6
=> (1 2 3)
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/hy/cmdline.py", line 102, in runsource
    ast_callback)
  File "/usr/local/lib/python3.5/dist-packages/hy/importer.py", line 176, in hy_eval
    return eval(ast_compile(expr, "<eval>", "eval"), namespace)
  File "<eval>", line 1, in <module>
TypeError: 'int' object is not callable

Im zweiten Beispiel haben wir "1 (* [2, 3])" in Python ausgewertet, und natürlich ist "1" nicht "aufrufbar", sodass ein Fehler auftritt. Verwenden Sie das Anführungszeichen ('), wenn Sie nicht als Funktion auswerten möchten.

Lisp-Liste mit Zitaten


=> '(1 2 3)
(1 2 3)

[...] Stellt eine sogenannte Liste in Python dar. Es wird nach Clojure auch als Vektor bezeichnet. Dies entspricht der oben zitierten * Lisp-Liste *.

Liste von Python


=> [1 2 3]
[1, 2, 3]
=> (= [1 2 3] '(1 2 3))
True

{...} Wie Python verwendet es ein Wörterbuch (dict). Ordnen Sie die Schlüssel und Elemente abwechselnd an.

dict


=> {"a" 1 "b" 2}
{'b': 2, 'a': 1}

Der Schlüssel kann auch die Form ": Schlüssel" haben.

diktiere Teil 2


=> {:a 1 :b 2}
{'\ufdd0:a': 1, '\ufdd0:b': 2}

Verwenden Sie get, um auf das Element zuzugreifen.

Zugriff auf Elemente des Diktats


=> (get {"a" 1 "b" 2} "a")
1
=> (get {:a 1 :b 2} :a)
1

Auch bei der zweiten Schreibmethode (: key) ist der folgende Zugriff möglich.

Greifen Sie auf die Elemente von Diktat 2 zu


=> (get {:a 1 :b 2} :a)
1
=> (:a {:a 1 :b 2})
1

Zusammenfassung

Die Tabelle bis zu diesem Punkt ist zusammengefasst. Auch wenn ich es nicht erklärt habe, ist der Tapple auch in der Tabelle enthalten.

Ausdruck in Hy Entsprechende Python-Darstellung
aufführen
(function arg1 arg2 ...)
Funktionsaufruf
function(*[args1, arg2, ...])
Zitierte Liste
'(elem1 elem2 ...)
aufführen
[elem1, elem2, ...]
Vektor
[elem1 elem2 ...]
aufführen
[elem1, elem2, ...]
Taple
(, elem1 elem2 ...)
Taple
(elem1, elem2, ..., )
Wörterbuch 1
{"key1" elem1 "key2" elem2 ...}
Wörterbuch
{"key1": elem1, "key2": elem2, ...}
Wörterbuch Teil 2
{:key1 elem1 :key2 elem2 ...}
Wörterbuch
{"key1": elem1, "key2": elem2, ...}

Funktionsüberlastung (Mehrfachdefinition)

In Python ist es im Gegensatz zu C ++ und Java nicht möglich, den Hauptteil einer Funktion je nach Art und Anzahl der Argumente zu wechseln. Hy hat Makros, um dies in den Modulen unter "hy.contrib" zu erreichen.

hy.contrib.multi.defn Das eingebaute Makro defn wird erweitert, um Polymorphismus um die Anzahl der Argumente zu realisieren.

Zahlenüberladung durch defn


(require [hy.contrib.multi [defn]])

(defn function
  ([a](+ "a = " (str a)))
  ([a b](+ "a = " (str a) ", b = " (str b))))

(print (function 3))
;; > a = 3
(print (function 3 4))
;; a = 3, b = 4

Im obigen Beispiel wird der Prozess zwischen dem Fall, in dem die Anzahl der Argumente eins ist, und dem Fall, in dem die Anzahl der Argumente zwei ist, umgeschaltet. Bitte seien Sie versichert, dass Sie es problemlos verwenden können, wenn Sie es auf die gleiche Weise wie normales "defn" verwenden.

hy.contrib.multi.defmulti, defmethod, default-method Realisiert Spezialisierung durch Mehrfachversand. Es ist eine sogenannte Multi-Methode.

Multi-Methode von defmulti


(require [hy.contrib.multi [defmulti defmethod default-method]])

(defmulti add [x y](, (type x) (type y)))

(defmethod add (, int str) [x y]
  (+ (str x) y))

(defmethod add (, str int) [x y]
  (+ x (str y)))

(default-method add [x y]
  (+ x y))

(print (add 1 "st"))
;; > 1st
(print (add "FF" 14))
;; > FF14
(print (add 2 4))
;; > 6
(print (add "Hello, " "world!"))
;; > "Hello, world!"

Das Makro defmulti definiert die Elemente, die für die Argumentbedingungen verwendet werden. In diesem Fall versenden wir mit einem Tapple "(, (Typ x) (Typ y))", das zwei Argumente akzeptiert und den Typ des Arguments speichert. Das Makro defmethod legt Bedingungen fest und definiert den Ausführungsinhalt für jede Bedingung. Das Makro "Standardmethode" kann auch definieren, was zu tun ist, wenn keine der Bedingungen erfüllt ist. Im obigen Beispiel wird der Typ als Trigger verwendet, es kann jedoch alles ausgelöst werden. Der folgende Code ist beispielsweise in Ordnung.

Multi-Methode von defmulti Teil 2


(require [hy.contrib.multi [defmulti defmethod default-method]])

(defmulti funtion [&rest args](first args))

(defmethod funtion 1 [&rest args]
  (print "the list of arguments starts with 1"))

(defmethod funtion 2 [&rest args]
  (print "the list of arguments starts with 2"))

(default-method funtion [&rest args]
  (print "the list of arguments starts with something other than 1 and 2"))

(funtion 1 3 4)
;; > the list of arguments starts with 1
(funtion 2 3)
;; > the list of arguments starts with 2
(funtion 4 8 9 0)
;; > the list of arguments starts with something other than 1 and 2

Im obigen Beispiel werden mehrere Argumente empfangen und das erste Element gesendet.

Verzögerungssequenz

Es ist wie bei einem Python-Generator, aber im Gegensatz zu einem Generator können Sie immer wieder auf dieselben Elemente zugreifen. Natürlich wird die Verzögerung wie der Generator ausgewertet. Kurz gesagt, es ist wie eine Liste mit Verzögerungsbewertung + Memos. Sie kann mit dem Makro "hy.contrib.sequences.defseq" definiert werden. Zum Beispiel kann Fibonacci wie folgt geschrieben werden.

Fibonacci mit verzögerter Sequenz


(require [hy.contrib.sequences [defseq]])
(import [hy.contrib.sequences [Sequence]])
;;Da es nach der Makroerweiterung verwendet wird, muss es importiert werden.

(defseq fibonacci [n]
  (if (<= n 1) n
      (+ (get fibonacci (- n 1)) (get fibonacci (- n 2)))))

(print (get fibonacci 100))
;; > 354224848179261915075

Der obige Code endet dank der verzögerten Auswertung in Millisekunden, aber das normale Schreiben mit einer rekursiven Funktion ist furchtbar zeitaufwändig.

Vorhergehende Punktsyntax (Postskriptum 2017/06/06)

In Hy können Sie * führende Punktsyntax * für Methodenaufrufe verwenden. Ein Syntaxzucker, mit dem Sie "(object.method args ...)" als "(.method object args ...)" schreiben können.

Vorhergehende Punktsyntax (Methodenaufruf)


=> (def a [1 2 3])
=> (.append a 4)
=> a
[1, 2, 3, 4]

Vorhergehende Punktsyntax (Zugriff auf den Modul-Namespace)


=> (import ast)
=> (.parse ast "print(\"Hello, world!\")" :mode "eval")
<_ast.Expression object at 0xb6a2daec>

Thread-Makro (2017/06/06 Nachtrag)

Wie am Ende von Tutorial erwähnt, verfügt Hy über eine sehr nützliche Funktion namens Thread-Makro, die die Lesbarkeit verbessert. Dies wird von Clojure geerbt. Es gibt verschiedene Arten, daher werde ich sie einzeln erklären.

->, ->> Sie können (func3 (func2 (func1))) als (-> func1 func2 func3) schreiben. Wenn ->, wird es als erstes Argument des folgenden Ausdrucks verkettet, und wenn - >>, wird es als letztes Argument verkettet. Ein konkretes Beispiel wird gezeigt.

->Wann->>Beispiel


=> (def a 8.)
=> (-> a (/ 4) (- 1)) ;; (- (/ a 4) 1)
1.0
=> (->> a (/ 4) (- 1)) ;; (- 1 (/ 4 a))
0.5

as-> Mit -> und- >>können Sie Argumente nur am Anfang oder Ende übergeben. Es kann nicht behandelt werden, wenn Sie es in der Mitte übergeben möchten oder wenn sich die zu übergebende Position je nach Funktion ändert. Hier kommt as-> ins Spiel.

as->Beispiel


=> (as-> a it
...      (/ it 4)
...      (- 1 it))
-1.0

Hier wird "a" vorübergehend "es" genannt.

doto Die Haarfarbe ist etwas anders, aber ich werde sie alle zusammen vorstellen. Es ist wie die With-Syntax in D, die eine Reihe von Methodenaufrufen für ein einzelnes Objekt vereinfacht. Sie können "(obj.method1) (obj.method2) ..." als "(do to obj .method1 .method2 ...)" schreiben.

Doto Beispiel


=> (doto [2 3](.append 1) .sort)
[1, 2, 3]

Verwendung von Thread-Makros

Dies ist besonders nützlich, wenn die Klammern tief verschachtelt sind. In Python gibt es viele Fälle, in denen Sie Ausdrücke schreiben können, die nicht gut genug sind. Betrachten Sie ein Beispiel für die Konvertierung von "Tanaka Taro" in "Taro Tanaka".

Taro Tanaka in Python


" ".join(map(str.capitalize, reversed("tanaka taro".split())))

Es ist etwas mühsam, dem Verarbeitungsablauf zu folgen. Mit Hy können Sie dasselbe wie folgt tun.

Taro Tanaka in Hy


(->> "tanaka taro" .split reversed (map str.capitalize) (.join " "))

Es sieht nicht nur sehr ordentlich aus, sondern der Prozessablauf ist jetzt von links nach rechts fließend. Kurz gesagt, Thread-Makros ähneln Rubys Methodenketten und UFCS in D-Sprache. Die Lesbarkeit wird erheblich verbessert. Verwenden Sie sie daher positiv.

abschließend

Wenn Sie an etwas anderes denken, werde ich es hinzufügen. Wenn Sie Fehler haben, lassen Sie es uns bitte wissen.

Recommended Posts

Erste Schritte mit Lisp für Pythonista: Ergänzung
Erste Schritte mit Julia für Pythonista
Erste Schritte mit Python für PHPer-Funktionen
Erste Schritte mit Python für PHPer-Super Basics
Erste Schritte mit Android!
1.1 Erste Schritte mit Python
Erste Schritte mit Python
Erste Schritte mit Django 1
Einführung in die Optimierung
Erste Schritte mit Numpy
Erste Schritte mit Spark
Erste Schritte mit Python
Erste Schritte mit Pydantic
Erste Schritte mit Jython
Erste Schritte mit Django 2
[Übersetzung] Erste Schritte mit Rust für Python-Programmierer
Einstellungen für den Einstieg in MongoDB mit Python
Übersetzen Erste Schritte mit TensorFlow
Einführung in Python-Funktionen
Einführung in Tkinter 2: Button
Erste Schritte mit Go Assembly
Erste Schritte mit PKI mit Golang ―― 4
Erste Schritte mit Python Django (1)
Erste Schritte mit Python Django (4)
Erste Schritte mit Python Django (3)
Einführung in Python Django (6)
Erste Schritte mit Django mit PyCharm
Erste Schritte mit Python Django (5)
Erste Schritte mit Python Responder v2
Einführung in Git (1) History-Speicher
Erste Schritte mit Sphinx. Generieren Sie Docstring mit Sphinx
Erste Schritte mit Python-Webanwendungen
Erste Schritte mit Sparse Matrix mit scipy.sparse
Erste Schritte mit Python Grundlagen von Python
Erste Schritte mit der Cisco Spark REST-API
Beginnend mit USD unter Windows
Erste Schritte mit genetischen Python-Algorithmen
Erste Schritte mit Python 3.8 unter Windows
Erste Schritte mit der CPU-Diebstahlzeit
Erstellen einer Windows 7-Umgebung für eine Einführung in das maschinelle Lernen mit Python
Erste Schritte mit Python3 # 1 Grundkenntnisse erlernen
Erste Schritte mit Python Web Scraping Practice
Erste Schritte mit Python Web Scraping Practice
Erste Schritte mit Dynamo von Python Boto
Erste Schritte mit Heroku, Bereitstellen der Flaschen-App
Erste Schritte mit TDD mit Cyber-dojo bei MobPro
Erste Schritte mit Python mit 100 Klopfen bei der Sprachverarbeitung
Erste Schritte mit Processing und p5.js (für diejenigen, die andere Sprachen beherrschen) 02
MongoDB-Grundlagen: Erste Schritte mit CRUD mit JAVA
Erste Schritte mit dem Zeichnen mit matplotlib: Schreiben einfacher Funktionen
Erste Schritte mit der japanischen Übersetzung des Keras Sequential-Modells
Einführung in die Verarbeitung und p5.js (für diejenigen, die andere Sprachen beherrschen) 01
Django Erste Schritte Teil 2 mit dem Eclipse Plugin (PyDev)
Erste Schritte mit AWS IoT in Python
Erste Schritte mit Pythons Ast-Modul (Verwenden von NodeVisitor)
~ Tipps für Python-Anfänger mit Liebe von Pythonista ② ~
Materialien zum Lesen, wenn Sie mit Python beginnen