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 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 ...)
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.
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'>
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.
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
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 ...) |
Funktionsaufruffunction(*[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, ...} |
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.
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.
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>
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]
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.
Wenn Sie an etwas anderes denken, werde ich es hinzufügen. Wenn Sie Fehler haben, lassen Sie es uns bitte wissen.
Recommended Posts