J'ai réfléchi à la façon dont j'allais concevoir la gamme "parfaite" littérale si je devais concevoir une langue. Pour vous qui ne connaissez pas, connaissez un littéral de plage dans une instruction qui représente une plage de valeurs, comme 1-4. Ils sont le plus souvent utilisés dans les boucles for / foreach
Il semble qu'il y ait quelques problèmes à prendre en compte
Prise en charge de plages inclusives et exclusives, le virement de +1 ou -1 vers les points de terminaison semble un peu fugace et sujet aux erreurs.
Prise en charge de la progression, vous pouvez donc créer une plage de nombres pairs ou impairs, par exemple
Lisibilité, il doit être facile de voir ce que le littéral de plage décrit
Sans ambiguïté, il devrait être parfaitement sans ambiguïté ce que la gamme littérale décrit
La valeur par défaut devrait probablement être comprise entre inclusive et exclusive, car c'est ce qui est utilisé dans la plupart des cas pour boucler sur des tableaux, etc.
Quoi qu'il en soit, un exemple de littéral de plage que j'ai vu est Ruby qui est sous la forme de 1..3 pour une plage exclusive (à la fin) et 1 ... 3 pour une plage inclusive (à la fin). Vous pouvez également faire 1..10. étape (5). Après mûre réflexion, j'ai trouvé cependant quelques choses que je n'aimais pas dans cette approche (de ma connaissance limitée du rubis)
Vous pouvez seulement décrire inclusif et exclusif pour la fin. Tout en décrivant la plupart des scénarios, cela semble un peu incohérent.
Variant de seulement un supplémentaire. semble être une recette pour rendre difficile de voir si une gamme est inclusive ou exclusive. Je ne sais pas pour vous mais les points ont tendance à devenir flous :)
L'ajout d'une méthode comme la notation pour les plages semble mélanger la notion de littéral avec celle d'une classe qui semble un peu incohérente (même si les plages sont compilées dans une classe)
Quoi qu'il en soit, après avoir réfléchi à différentes alternatives. Je suis venu avec cette
- [5..1] 5,4,3,2,1
- [1..5 [ 1,2,3,4
- ] 1..5] 2,3,4,5
- [ 0..5..20] 0,5,10,15,20
et ainsi de suite. Je l'aime parce que [dénonce normalement un ensemble et cela s'intègre un peu à cela, même si cela contraste avec un ensemble serait commandé.
Une chose qui me déchire un peu, c'est de rendre les indicateurs exclusifs / inclusifs obligatoires ou non, c'est-à-dire que si vous écrivez juste 1..5, la valeur par défaut serait 1,2,3,4 car c'est le cas le plus courant avec les tableaux, etc. C'est plus facile et plus lisible, mais moins spécifique et si vous deviez écrire [1..5 [vous apprenez tôt comment ils fonctionnent.
Alors que pensez-vous, ai-je couvert la plupart des bases, oublié quelque chose? rendriez-vous le [] obligatoire? Souhaitez-vous concevoir des littéraux de plage différemment dans votre langage de programmation?
Candidats
- style de support: [0..10 [ , avec étape: [0..5..20 [
- notation d'intervalle: [0..10) avec étape: [0..5..20)
- exclamation pour exlusif. 0 ..! 10, avec pas: 0..5 ..! 20
- avec une étape différente. 0 ..! 20, 5
- cependant, cela rendrait la valeur par défaut * 0..10 ' inclusive-inclusive
- wordy: [0 à! 20 par 5]
Je dois dire que mon préféré est jusqu'ici 0 ..! 10 et 0..5 ..! 20 , je souhaite juste que le 0..10 par défaut inclusif-exclusif soit plus logique
1,5,10,15,20
Écart 4, 5, 5, 5?!Réponses:
Pourquoi inventer ce qui existe déjà en mathématiques?
La notation des intervalles
Cela devrait couvrir votre point d'ambiguïté tel qu'il existe déjà.
Votre seul problème serait de définir la progression. Peut-être que quelque chose d'autre en mathématiques peut aider à cela?
la source
[1..5[
) confondra les éditeurs au moins autant que la notation d'intervalle standard.!
pour exclure le premier ou le dernier élément pourrait être une bonne chose .Avez-vous vu les gammes Haskell? Leur idée des étapes est similaire à la vôtre (au milieu) mais indiquée par une différence syntaxique (de la réponse de @ luqui ):
Je trouve cette notation très intuitive: vous commencez à énumérer et à sauter le corps pour marquer où il doit se terminer.
Il ne couvre pas le cas de "exclusif", mais franchement, je préfère être clair une fois sur le comportement (spécifier quelle limite est inclusive et laquelle est exclusive), et attend de l'utilisateur qu'il fasse des ajustements à moins que la syntaxe ne soit extrêmement claire (et ne confond pas les éditeurs indépendants de la langue).
la source
Vous devriez lire les listes de compréhension dans les langues qui les proposent.
Python, par exemple, couvre assez bien vos cas avec la
range()
fonction et la compréhension de la liste des cas trop complexes pour s'exprimerrange()
.la source
Je pense que votre notation est loin d'être sans ambiguïté. Intuitivement,
[0..5..20]
cela ne me ressemble pas à une plage avec une largeur de pas = 5. Cela échoue même dans certains cas d'angle: qu'en est-il de l'expression de l'ensemble (0,2) -[0..2..2]
ou que dois-je mettre au milieu?Je pense que la notation de tranche de Python est une approche solide:
[start:end:step]
(l'étape étant facultative).Si vous avez vraiment besoin de la prise en charge de plages exclusives et inclusives, j'utiliserais la notation de plage standard (c'est-à-dire en utilisant
(
et[
) à moins que cela n'introduise des ambiguïtés syntaxiques dans votre langue.la source
[]
,[[
,]]
et][
, sans parenthèses ... et notre norme est mieux, bien sûr;)Je pense que lorsque vous définissez une troisième valeur d'incrément, vous feriez mieux de l'ajouter à la fin plutôt qu'au milieu, car il s'agit d'une valeur facultative, et semble plus intuitif pour les programmeurs chevronnés que d'ajouter un 3e argument facultatif au milieu .
au lieu de [1..5..20], vous pourriez faire quelque chose comme [1..20] [5] ou [1..20,5]
la source
Pourquoi ne pas simplement utiliser [1..4], [2..5], [2..4]? L'exclusion des plages n'offre pas beaucoup d'avantages. Vous n'avez pas besoin d'écrire MIN + 1 ou MAX-1, oui, mais ils ne l'interdisent pas de toute façon. Trop de variations, à mon humble avis. Ma langue de prédilection, la scala, a (1 à 3) et (1 à 3) [= (1 à 2)] mais cela m'a juste dérouté au début. Maintenant, j'utilise toujours 'x to y' et je sais donc que l'option que je n'utilise pas est celle qui exclut, mais bien sûr, je ne bénéficie pas d'une option que je n'utilise pas.
est bien sûr (1 à MAX) (x => y = (MAX + 1) - x) mais c'est beaucoup plus standard et pas convivial.
est bien sûr (0 à 4) (x => y = x * 5) n'est pas tellement passe-partout. Contestable.
la source
Et quelque chose comme ça:
Le
i
ete
dans la deuxième paire de crochets indique si le début ou la fin de la plage est inclusif ou exclusif (ou vous pouvez utiliserincl
, etexcl
si vous voulez être plus clair). leby 5
indique l'intervalle de pas. Le premier et le dernier exemple incluent la première et la dernière valeur, j'ai donc omis le[i,i]
, qui, je pense, serait un comportement par défaut supposé OK.Les valeurs par défaut peuvent être
[i,i]
pour le spécificateur inclusif / exclusif etby 1
pour le spécificateur d'étape.Normalement, j'aurais suggéré la notation standard impliquant
(
et[
comme mentionné par @Dan McGrath, mais je conviens que dans le code, cela pourrait sembler déroutant.la source
Et le gagnant est
Désolé d'avoir choisi ma propre solution, j'apprécie vraiment tous les commentaires et commentaires et veuillez critiquer cette solution si vous trouvez quelque chose de mal avec elle
J'ai donc décidé d'aller avec:
Comme vous pouvez le voir, l'inclusion est la valeur par défaut dans les deux sens, c'est ce qui est intuitivement le plus logique, en particulier lorsque vous utilisez le pas. Vous pouvez utiliser ! pour faire une fin exclusive.
L'inconvénient est que, normalement, vous souhaitez utiliser l'exclusivité lorsque vous travaillez contre un tableau, mais là encore, la plupart du temps, vous devriez probablement utiliser quelque chose comme for-each dans ces cas. Si vous avez vraiment vraiment besoin de travailler contre l'index, l'analyseur pourrait reconnaître quand vous avez peut-être oublié le marqueur d'exclusion à la fin et émettre un avertissement
J'ai choisi d'utiliser .. des deux côtés de la variable step au lieu d'utiliser une virgule ou toute autre chose car c'est ce qui semblait le plus propre et j'espère que c'est le plus lisible.
J'ai également ajouté une syntaxe avec des virgules pour pouvoir créer des plages où différentes parties ont des étapes différentes
la source
Je n'utiliserais pas le formulaire '[1..5 [' pour l'une des mêmes raisons pour lesquelles vous évitez de mélanger les parenthèses et les accolades - cela confondra la correspondance des accolades de la plupart des éditeurs existants. Utilisez peut-être un marqueur à l'intérieur des accolades, comme «[1 .. | 5]».
L'autre chose à considérer est le comportement des méthodes pour obtenir les limites. Par exemple, «début» / «fin» vs «premier» / «dernier» vs «min» / «max». Ils doivent être raisonnables pour les limites inclusives et exclusives, ainsi que pour celles qui ont une taille de pas.
la source
Ruby a une notation et un objet Range qui fonctionne. Essentiellement, cela ressemble à ceci:
Avec Ruby, la taille des pas n'est pas une fonction de la plage, mais plutôt une fonction d'itération à travers la plage. Nous pourrions utiliser la même plage ci-dessus et l'itérer différemment si nous voulions:
Voici donc des éléments à considérer:
BTW, les plages sont plutôt bien si vous autorisez leur inclusion dans une instruction switch comme Ruby le fait:
Je ne dis pas que l'objet de gamme de Ruby est la fin de tout et soyez tout, mais c'est une implémentation fonctionnelle du concept dont vous parlez. Jouez avec pour voir ce que vous aimez, n'aimez pas et feriez différemment.
la source
Anyways, one example of range literal I've seen is Ruby which is in the form of 1..3 for an exclusive (on the end) range and 1...3 for inclusive (on the end). You can also do 1..10.step(5).
Une solution que j'envisagerais certainement est d'utiliser la surcharge de l'opérateur pour permettre par exemple
Il ne serait pas nécessairement immédiatement transparent pour tout le monde, mais une fois qu'ils s'arrêteront et penseront que j'espère que la plupart des programmeurs le comprendront et que les personnes qui utilisent régulièrement le langage l'apprendront simplement comme un idiome.
Pour clarifier, le résultat serait de
[1, 6, 11, 16]
lever la multiplication puis l'addition sur la plage. Je n'avais pas réalisé que cela pouvait être ambigu pour les utilisateurs de Python; Je considère les plages comme des sous-ensembles de commandes totales plutôt que comme des listes. et répéter un ensemble n'a pas de sens.la source
list expression * 5
pourrait également signifier "répéter la valeur delist expression
5 fois", comme c'est le cas en Python.1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3
?1,3,6,9,12
?5,10,15
? autre chose, peut-être? Quoi qu'il en soit, je trouve cette notation complètement contre-intuitive. On dirait que c'est peut-être une sorte d'opération étrange du pointeur C ...