Je veux dire de cette façon:
<?php
$number1 = 5; // (Type 'Int')
$operator1 = +; // (Type non-existent 'Operator')
$number2 = 5; // (Type 'Int')
$operator2 = *; // (Type non-existent 'Operator')
$number3 = 8; // (Type 'Int')
$test = $number1 $operator1 $number2 $operator2 $number3; //5 + 5 * 8.
var_dump($test);
?>
Mais aussi de cette façon:
<?php
$number1 = 5;
$number3 = 9;
$operator1 = <;
if ($number1 $operator1 $number3) { //5 < 9 (true)
echo 'true';
}
?>
Il ne semble pas que certaines langues aient cela - y a-t-il une bonne raison pour laquelle elles ne le font pas?
Les opérateurs ne sont que des fonctions sous des noms amusants, avec une syntaxe spéciale autour.
Dans de nombreux langages, aussi variés que C++ et Python, vous pouvez redéfinir les opérateurs en remplaçant les méthodes spéciales de votre classe. Ensuite, les opérateurs standard (par exemple +
) fonctionne selon la logique que vous fournissez (par exemple, concaténation de chaînes ou ajout de matrices ou autre).
Étant donné que ces fonctions définissant l'opérateur ne sont que des méthodes, vous pouvez les transmettre comme vous le feriez pour une fonction:
# python
action = int.__add__
result = action(3, 5)
assert result == 8
D'autres langages vous permettent de définir directement de nouveaux opérateurs en tant que fonctions et de les utiliser sous forme d'infixe.
-- haskell
plus a b = a + b -- a normal function
3 `plus` 5 == 8 -- True
(+++) a b = a + b -- a funny name made of non-letters
3 +++ 5 == 8 -- True
let action = (+)
1 `action` 3 == 4 -- True
Malheureusement, je ne sais pas si PHP supporte quelque chose comme ça, et si le supporter serait une bonne chose. Utilisez une fonction simple, elle est plus lisible que $foo $operator $bar
.
Il existe de nombreuses langues qui permettent une sorte de métaprogrammation . En particulier, je suis surpris de ne voir aucune réponse parler de la famille de langues LISP .
De wikipedia:
La métaprogrammation est l'écriture de programmes informatiques avec la capacité de traiter les programmes comme leurs données.
Plus loin dans le texte:
LISP est probablement le langage par excellence avec des installations de métaprogrammation, à la fois en raison de sa priorité historique et en raison de la simplicité et de la puissance de sa métaprogrammation.
Langues LISP
Une introduction rapide et inventée au LISP suit.
Une façon de voir le code est une suite d'instructions: faites ceci, puis faites cela, puis faites cette autre chose ... Ceci est une liste! Une liste de choses à faire pour le programme. Et bien sûr, vous pouvez avoir des listes à l'intérieur des listes pour représenter les boucles, etc.
Si nous représentons une liste contenant les éléments a, b, c, d comme ceci: (abcd) nous obtenons quelque chose qui ressemble à un appel de fonction LISP, où a
est la fonction et b
, c
, d
sont les arguments. Si en fait le "Hello World!" Typique le programme pourrait s'écrire ainsi: (println "Hello World!")
Bien sûr, b
, c
ou d
pourraient également être des listes qui correspondent à quelque chose. Le texte suivant: (println "I can add :" (+ 1 3) )
Afficherait alors "" Je peux ajouter: 4 ".
Ainsi, un programme est une série de listes imbriquées et le premier élément est une fonction. La bonne nouvelle est que nous pouvons manipuler des listes! Nous pouvons donc manipuler des langages de programmation.
L'avantage LISP
Les lisps ne sont pas autant des langages de programmation qu'une boîte à outils pour créer des langages de programmation. Un langage de programmation programmable.
Il n'est pas seulement beaucoup plus facile en Lisps de créer de nouveaux opérateurs, il est également presque impossible d'écrire certains opérateurs dans d'autres langues car les arguments sont évalués lorsqu'ils sont passés à la fonction.
Par exemple, dans un langage de type C, disons que vous voulez écrire vous-même un opérateur if
, quelque chose comme:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
Dans ce cas, les deux arguments seront évalués et imprimés, dans un ordre dépendant de l'ordre d'évaluation des arguments.
En Lisps, écrire un opérateur (nous l'appelons une macro) et écrire une fonction, c'est à peu près la même chose et utilisé de la même manière. La principale différence est que les paramètres d'une macro ne sont pas évalués avant d'être passés en arguments à la macro. Ceci est essentiel pour pouvoir écrire certains opérateurs, comme le if
ci-dessus.
Langues du monde réel
Montrer comment exactement est un peu hors de portée ici, mais je vous encourage à essayer de programmer dans un LISP pour en savoir plus. Par exemple, vous pouvez consulter:
Oh et en passant, LISP signifie LISt Processing.
Concernant vos exemples
Je vais donner des exemples en utilisant Clojure ci-dessous:
Si vous pouvez écrire une fonction add
dans Clojure (defn add [a b] ...your-implementation-here... )
, Vous pouvez la nommer +
Ainsi (defn + [a b] ...your-implementation-here... )
. C'est en fait ce qui se fait dans le implémentation réelle (le corps de la fonction est un peu plus impliqué mais la définition est essentiellement la même que celle que j'ai écrite ci-dessus).
Et la notation infixe? Eh bien, Clojure utilise une notation prefix
(ou polonaise), donc nous pourrions créer une macro infix-to-prefix
Qui transformerait le code préfixé en code Clojure. Ce qui est en fait étonnamment facile (c'est en fait l'un des macro exercices dans les koans clojure)! Il peut également être vu dans la nature, par exemple voir macro Incanter $=
.
Voici la version la plus simple des koans expliquée:
(defmacro infix [form]
(list (second form) (first form) (nth form 2)))
;; takes a form (ie. some code) as parameter
;; and returns a list (ie. some other code)
;; where the first element is the second element from the original form
;; and the second element is the first element from the original form
;; and the third element is the third element from the original form (indexes start at 0)
;; example :
;; (infix (9 + 1))
;; will become (+ 9 1) which is valid Clojure code and will be executed to give 10 as a result
Pour aller encore plus loin, certains citations LISP :
"Ce qui fait la particularité de LISP, c'est qu'il est conçu pour évoluer. Vous pouvez utiliser LISP pour définir de nouveaux opérateurs LISP. À mesure que les nouvelles abstractions deviennent populaires (programmation orientée objet, par exemple), il s'avère toujours facile de les implémenter dans LISP. Comme l'ADN, un tel langage ne se démode pas. "
- Paul Graham, LISP commun ANSI
"La programmation dans LISP, c'est comme jouer avec les forces primordiales de l'univers. Cela ressemble à un éclair entre vos doigts. Aucune autre langue ne se sent même proche. "
- Glenn Ehrlich, route vers LISP
$test = $number1 $operator1 $number2 $operator2 $number3;
La plupart des implémentations de langues ont une étape où un analyseur analyse votre code et construit une arborescence à partir de celui-ci. Ainsi, par exemple, l'expression 5 + 5 * 8
serait analysé comme
+
/ \
5 *
/ \
8 8
grâce à la connaissance du compilateur sur les précédents. Si vous lui fournissiez des variables à la place des opérateurs, il ne connaîtrait pas l'ordre correct des opérations avant d'exécuter le code. Pour la plupart des implémentations, ce serait un problème grave, donc la plupart des langues ne le permettent pas.
Vous pourriez bien sûr concevoir un langage dans lequel l'analyseur analyse simplement ce qui précède comme une séquence d'expressions et d'opérateurs, à trier et à évaluer au moment de l'exécution. Vraisemblablement, il n'y a tout simplement pas beaucoup d'application pour cela.
De nombreux langages de script permettent l'évaluation d'expressions arbitraires (ou du moins d'expressions arithmétiques arbitraires comme dans le cas de expr
) lors de l'exécution. Là, vous pouvez simplement combiner vos nombres et opérateurs en une seule expression et laisser le langage évaluer cela. Dans PHP (et bien d'autres) cette fonction est appelée eval
.
$test = eval("$number1 $operator1 $number2 $operator2 $number3");
Il existe également des langages qui permettent la génération de code au moment de la compilation. Le expression de mixin en D me vient à l'esprit, où je crois que vous pourriez écrire quelque chose comme
test = mixin("number1 " + operator1 + " number2 " + operator2 + "number3");
Ici operator1
et operator2
devrait être des constantes de chaîne connues au moment de la compilation, par exemple paramètres de modèle. number1
, number2
et number3
ont été laissés en tant que variables d'exécution normales.
D'autres réponses ont déjà discuté des différentes façons dont un opérateur et une fonction sont plus ou moins la même chose, selon la langue. Mais généralement, il existe une différence syntaxique entre un symbole opérateur d'infixe intégré comme +
et un appelable nommé comme operator1
. Je vais laisser les détails à ces autres réponses.
ALGOL 68 avait exactement cette caractéristique. Votre exemple dans ALGOL 68 ressemblerait à ceci:
int numéro1 = 5; ¢ (Tapez 'Int') ¢
op operator1 = int ( int a, b) a + b; ¢ (Tapez 'Operator' inexistant) ¢
prio operator1 = 4;
int numéro2 = 5; ¢ (Tapez 'Int') ¢
op operator2 = int ( int a, b) a * b; ¢ (Tapez 'Operator' inexistant) ¢
prio operator2 = 5;
int numéro3 = 8; ¢ (Tapez 'Int') ¢int test = number1 operator1 numéro2 opérateur2 numéro3; ¢ 5 + 5 * 8. ¢
var_dump ( test);
Votre deuxième exemple ressemblerait à ceci:
int number4 = 9;
op operator3 = bool ( int a, b) a < b;
prio operator3 = 3;
if number1 $ operator3 numéro4 puis ¢ 5 <9 (vrai) ¢
print ( true )
fi
Vous remarquerez que les symboles d'opérateur sont définis et des corps de méthode affectés qui contiennent l'opération souhaitée. Les opérateurs et leur opérande sont tous dactylographiés et les opérateurs peuvent se voir attribuer des priorités afin que l'évaluation se déroule dans le bon ordre. Vous pouvez également remarquer qu'il existe une légère différence de police entre le symbole de l'opérateur et un symbole de variable.
En fait, bien que la langue soit écrite à l'aide de polices, les machines de l'époque ne pouvaient pas gérer les polices (bande de papier et cartes perforées), et stropping était utilisé. Le programme serait probablement entré comme:
'INT' NUMBER4 = 9;
'OP' 'OPERATOR3' = 'BOOL' ('INT' A,B) A < B;
'PRIO' 'OPERATOR3' = 3;
'IF' NUMBER1 'OPERATOR3' NUMBER4 'THEN' 'C' 5 < 9 'C'
PRINT('TRUE')
'FI'
Vous pouvez également jouer à des jeux intéressants avec le langage lorsque vous pouvez définir vos propres symboles pour les opérateurs, que j'ai exploités une fois, il y a de nombreuses années ... [2].
Références:
[1] Introduction informelle à ALGOL 68 par C.H. Lindsey et S.G. van der Meulen, Hollande du Nord, 1971 .