Premiers pas avec Lisp pour Pythonista: Supplément

introduction

Ceci est un article supplémentaire à Introduction à Lisp pour Pythonista (traduction japonaise du tutoriel Hy). Dans Tutoriel Hy, la plupart du contenu était ** "Ce que vous écrivez en Python, écrivez ceci en Hy" **, mais cela aussi Certains endroits ne sont pas suffisants pour une utilisation pratique. Dans cet article, je voudrais fournir une explication supplémentaire des caractéristiques uniques de Hy, en d'autres termes, les caractéristiques de Hy ** et les caractéristiques uniques de Hy ** que Python n'a pas. Si vous lisez ceci, je pense qu'il suffit d'utiliser Hy au lieu de Python pour le moment.

Je veux le lire ensemble

J'ai trouvé les bons articles suivants autres que Qiita, alors veuillez vous y référer également. (Article précédent et couverture Moro, c'est plus utile ...)

Moule

Il prend en charge les types similaires à Python. Cependant, il existe quelques différences entre les séries Python 2.x et 3.x. Le comportement est le même, mais le type est différent.

Type entier

Il est long en Python 2.x et ʻint` en série 3.x.

Entier en Python2


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

Entier en Python 3


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

Type de chaîne

En Python 2.x, c'est ʻunicode, et dans la série 3.x, c'est str`.

Chaîne en Python2


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

Chaîne en Python 3


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

À propos, la chaîne de caractères est placée entre guillemets doubles (" ). Les guillemets (` ``) ne sont pas autorisés. De plus, contrairement à Python, les sauts au milieu sont autorisés.

nil Hy est Lisp, donc je ne pense pas que cela commencera sans rien. Cependant, Hy est également Python, il est donc plutôt compatible Python en termes de types. Par conséquent ** il n'y a pas de zéro **. Utilisez une liste vide ([] ou ()), un taple vide ((,)), False, None, etc., selon le contexte. Si vous êtes un Pythonista qui n'est pas Lisper, vous pouvez continuer comme avant.

Types de parenthèses

Comme Clojure, contrairement aux autres Lisps, ** il y a une distinction entre parenthèses **.

(...) Représente une liste. Cependant, comme il s'agit d'un concept légèrement différent de la liste de Python, nous l'appellerons * liste Lisp * par souci de distinction. Dans la liste * Lisp *, le premier élément est une fonction et les éléments restants sont appliqués en tant qu'arguments. Par conséquent, (function value1 value2 ...) est équivalent à function (* [value1, value2 ...]) en Python.

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

Dans le deuxième exemple, nous avons évalué «1 (* [2, 3])» en Python, et bien sûr «1» n'est pas «appelable», donc une erreur se produit. Utilisez la citation (`` '') lorsque vous ne souhaitez pas évaluer en tant que fonction.

Liste Lisp avec citations


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

[...] Représente une soi-disant liste en Python. On l'appelle aussi un vecteur, à la suite de Clojure. Ceci est équivalent à la liste * Lisp * citée ci-dessus.

Liste de Python


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

{...} Comme Python, il utilise un dictionnaire (dict). Disposez les touches et les éléments en alternance.

dict


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

La clé peut également être sous la forme «: clé».

dict partie 2


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

Utilisez get pour accéder à l'élément.

Accéder aux éléments de dict


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

De plus, dans le cas de la deuxième méthode d'écriture (: key), l'accès suivant est également possible.

Accéder aux éléments de dict # 2


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

Résumé

Le tableau jusqu'à présent est résumé. Je ne l'ai pas expliqué, mais j'inclus également des tapples dans le tableau.

Expression dans Hy Représentation Python correspondante
liste
(function arg1 arg2 ...)
Appel de fonction
function(*[args1, arg2, ...])
Liste citée
'(elem1 elem2 ...)
liste
[elem1, elem2, ...]
Vecteur
[elem1 elem2 ...]
liste
[elem1, elem2, ...]
Taple
(, elem1 elem2 ...)
Taple
(elem1, elem2, ..., )
Dictionnaire 1
{"key1" elem1 "key2" elem2 ...}
dictionnaire
{"key1": elem1, "key2": elem2, ...}
Dictionnaire partie 2
{:key1 elem1 :key2 elem2 ...}
dictionnaire
{"key1": elem1, "key2": elem2, ...}

Surcharge de fonction (définition multiple)

En Python, contrairement à C ++ et Java, il n'est pas possible de changer le corps d'une fonction en fonction du type et du nombre d'arguments. Hy a des macros pour y parvenir dans les modules sous hy.contrib.

hy.contrib.multi.defn La macro intégrée defn est étendue pour réaliser le polymorphisme par le nombre d'arguments.

Surcharge numérique par 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

Dans l'exemple ci-dessus, le processus bascule entre le cas où le nombre d'arguments est de un et le cas où le nombre d'arguments est de deux. Soyez assuré que vous pouvez l'utiliser tel quel sans aucun problème si vous l'utilisez de la même manière que la normale defn.

hy.contrib.multi.defmulti, defmethod, default-method Réalise la spécialisation par envoi multiple. C'est une soi-disant multi-méthode.

Multi-méthode par 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!"

La macro defmulti définit les éléments utilisés pour les conditions d'argument. Dans ce cas, nous distribuons avec un tapple (, (type x) (type y)) qui prend deux arguments et stocke les types de ces arguments. La macro defmethod définit les conditions et définit le contenu d'exécution pour chaque condition. De plus, la macro default-method peut définir ce qu'il faut faire si aucune des conditions n'est remplie. Dans l'exemple ci-dessus, le type est utilisé comme déclencheur, mais tout peut être déclenché. Par exemple, le code suivant est correct.

Multi-méthode par defmulti Partie 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

Dans l'exemple ci-dessus, plusieurs arguments sont reçus et le premier élément est distribué.

Séquence de retard

C'est comme un générateur Python, mais contrairement à un générateur, vous pouvez accéder aux mêmes éléments encore et encore. Bien entendu, le retard est évalué comme le générateur. En bref, c'est comme une liste avec évaluation des délais + mémos. Il peut être défini avec la macro hy.contrib.sequences.defseq. Par exemple, Fibonacci peut s'écrire comme suit.

Fibonacci avec séquence retardée


(require [hy.contrib.sequences [defseq]])
(import [hy.contrib.sequences [Sequence]])
;;Puisqu'il est utilisé après l'expansion de la macro, il doit être importé.

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

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

Le code ci-dessus se termine en milliseconde grâce à l'évaluation retardée, mais l'écrire normalement avec une fonction récursive prend énormément de temps.

Syntaxe du point précédent (post-scriptum du 06/06/2017)

Dans Hy, vous pouvez utiliser la * syntaxe de point de début * pour les appels de méthode. Un sucre de syntaxe qui vous permet d'écrire (object.method args ...) comme (.method object args ...).

Syntaxe du point précédent (appel de méthode)


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

Syntaxe du point précédent (accès à l'espace de noms du module)


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

Macro de discussion (post-scriptum du 06/06/2017)

Comme mentionné à la fin du Tutoriel, Hy a une fonction très utile appelée macro de thread qui améliore la lisibilité. Ceci est hérité de Clojure. Il existe plusieurs types, je vais donc les expliquer individuellement.

->, ->> Vous pouvez écrire (func3 (func2 (func1))) comme (-> func1 func2 func3). Si ->, il sera chaîné comme premier argument de l'expression suivante, et si - >>, il sera chaîné comme dernier argument. Un exemple concret est montré.

->Quand->>Exemple


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

as-> Avec -> et - >>, vous ne pouvez passer des arguments qu'au début ou à la fin. Il ne peut pas être manipulé lorsque vous souhaitez le passer au milieu ou lorsque la position à passer change en fonction de la fonction. C'est «as->» qui y joue un rôle actif.

as->Exemple


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

Ici, ʻa reçoit un nom temporaire de ʻit.

doto La couleur des cheveux est légèrement différente, mais je vais les présenter tous ensemble. C'est comme la syntaxe With en D, qui simplifie une série d'appels de méthode à un seul objet. Vous pouvez écrire (obj.method1) (obj.method2) ... comme (do to obj .method1 .method2 ...).

exemple doto


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

Comment utiliser les macros de thread

Ceci est particulièrement utile lorsque les parenthèses sont profondément imbriquées. En Python, il existe de nombreux cas où vous pouvez écrire des expressions qui ne sont pas assez bonnes. Prenons un exemple de conversion de «« tanaka taro »« en «Taro Tanaka» ».

Taro Tanaka en Python


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

Il est un peu gênant de suivre le flux de traitement. Vous pouvez faire la même chose avec Hy comme suit.

Taro Tanaka à Hy


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

Non seulement cela a l'air très soigné, mais le déroulement du processus est désormais fluide de gauche à droite. En bref, les macros de thread sont comme les chaînes de méthodes de Ruby et l'UFCS en langage D. La lisibilité sera grandement améliorée, alors utilisez-la de manière positive.

en conclusion

Si vous pensez à autre chose, je l’ajouterai. Si vous avez des erreurs, veuillez nous en informer.

Recommended Posts

Premiers pas avec Lisp pour Pythonista: Supplément
Premiers pas avec Julia pour Pythonista
Premiers pas avec Python pour les fonctions PHPer
Premiers pas avec Python pour PHPer-Super Basics
Premiers pas avec Android!
1.1 Premiers pas avec Python
Premiers pas avec Python
Premiers pas avec Django 1
Introduction à l'optimisation
Premiers pas avec Numpy
Premiers pas avec Spark
Premiers pas avec Python
Premiers pas avec Pydantic
Premiers pas avec Jython
Premiers pas avec Django 2
[Français] Premiers pas avec Rust pour les programmeurs Python
Paramètres pour démarrer avec MongoDB avec python
Traduire Premiers pas avec TensorFlow
Introduction aux fonctions Python
Introduction à Tkinter 2: Button
Premiers pas avec Go Assembly
Premiers pas avec PKI avec Golang ―― 4
Premiers pas avec Python Django (1)
Premiers pas avec Python Django (4)
Premiers pas avec Python Django (3)
Introduction à Python Django (6)
Premiers pas avec Django avec PyCharm
Premiers pas avec Python Django (5)
Premiers pas avec Python responder v2
Introduction à Git (1) Stockage d'historique
Premiers pas avec Sphinx. Générer docstring avec Sphinx
Premiers pas avec les applications Web Python
Premiers pas avec Sparse Matrix avec scipy.sparse
Premiers pas avec Python Bases de Python
Premiers pas avec Cisco Spark REST-API
Commençant par USD sur Windows
Premiers pas avec les algorithmes génétiques Python
Premiers pas avec Python 3.8 sous Windows
Premiers pas avec CPU Steal Time
Création d'un environnement Windows 7 pour une introduction à l'apprentissage automatique avec Python
Premiers pas avec python3 # 1 Apprenez les connaissances de base
Premiers pas avec Python Web Scraping Practice
Premiers pas avec Python Web Scraping Practice
Premiers pas avec Dynamo de Python boto
Premiers pas avec Heroku, déploiement de l'application Flask
Premiers pas avec TDD avec Cyber-dojo chez MobPro
Démarrer avec Python avec 100 coups sur le traitement du langage
Premiers pas avec Processing et p5.js (pour ceux qui ont fait d'autres langues) 02
Principes de base de MongoDB: Premiers pas avec CRUD avec JAVA
Premiers pas avec le dessin avec matplotlib: écrire des fonctions simples
Premiers pas avec la traduction japonaise du modèle séquentiel Keras
Introduction au traitement et p5.js (pour ceux qui ont fait d'autres langues) 01
Django Getting Started Part 2 avec eclipse Plugin (PyDev)
Premiers pas avec AWS IoT facilement en Python
Premiers pas avec le module ast de Python (à l'aide de NodeVisitor)
~ Conseils pour les débutants de Python donnés avec amour par Pythonista ② ~
Matériel à lire lors de la mise en route de Python