12
votes

DataType Scala pour la plage réelle numérique

Y a-t-il un type de scala idiomatique pour limiter une valeur de point flottante à une plage de flottille donnée définie par une limite inférieure supérieure?

Béton Je veux avoir un type de flotteur uniquement autorisé à avoir des valeurs comprises entre 0.0. et 1.0. P>

plus concret Je suis sur le point d'écrire une fonction qui prend une fonction Int et une autre fonction qui correspond à celle de la plage entre 0.0 et 1,0, en pseudo-scala: P>

def foo(x : Int, f : (Int => {0.0,...,1.0})) {
    // ....
}


2 commentaires

Avez-vous regardé Spire ?


semble prometteur, va vérifier!


3 Réponses :


8
votes

Je ne saurais pas comment le faire statiquement, sauf avec types dépendants ( Exemple ), quelle scala n'a pas. Si vous avez uniquement traité des constantes, il devrait être possible d'utiliser des macros ou un plug-in compilateur qui effectue les chèques nécessaires, mais si vous avez des expressions typées de float arbitraires, il est très probable que vous ayez à recourir à des contrôles d'exécution.

Voici une approche. Définissez une classe qui effectue une vérification d'exécution pour vous assurer que la valeur du flotteur est dans la plage requise: xxx

Vous pouvez l'utiliser comme suit: xxx

ou comme: xxx

Ce serait bien si on pouvait utiliser CLASSES DE VALEUR Pour obtenir des performances, mais l'appel à nécessite dans le constructeur (actuellement) interdit.


edit: Adressage des commentaires par @paradigmatic

Voici un argument intuitif Pourquoi les types en fonction des nombres naturels peuvent être codés dans un système de type qui ne supporte pas (entièrement) dépendant Types , mais des flotteurs à distance ne peuvent probablement pas: les nombres naturels sont un ensemble énumérable, ce qui permet d'encoder chaque élément comme Types dépendant du chemin à l'aide de numéros de PEERO . Les nombres réels, cependant, ne sont plus énormes, et il n'est donc plus possible de créer systématiquement des types correspondant à chaque élément des réels.

Maintenant, des flotteurs informatiques et des réels sont éventuellement des ensembles finis, mais Toujours un moyen d'être important d'être raisonnablement soumis à un système de type. L'ensemble de nombres naturels informatiques est bien sûr également très important et pose donc un problème pour l'arithmétique sur les chiffres de PEERNO codé en tant que types, voir le dernier paragraphe de Cet article . Cependant, je prétends qu'il suffit souvent de travailler avec le premier n (pour un nombre plutôt petit n ), comme, par exemple, en évidence par Hlistes . La réclamation correspondante des flotteurs est moins convaincante - serait-il préférable de coder 10 000 flottants compris entre 0,0 et 1,0, ou plutôt 10 000 entre 0,0 et 100,0?


11 commentaires

Il convient de noter que même si Scala avait des types dépendants pouvant exprimer cela, cela viendrait à un coût énorme. Les personnes qui veulent souvent des types restreints ne pensent souvent pas à la charge supplémentaire de la production de valeurs de ces types. Quelqu'un vous donne un float d'entrée? Assurez-vous d'avoir une procédure de test qui produit un flotteur dans votre gamme ou vous indique qu'il ne correspond pas. Faire des mathématiques compliquées sur une collection de flotteurs dont le résultat peut être montré? Vous devrez écrire une longue preuve (dans la langue) que le résultat s'adaptera toujours dans la gamme. Personnellement, j'adore le faire, mais c'est dur ...


Il y a dépend des types de Scala. Regardez la première réponse: Stackoverflow.com/Questtions/12935731/...


@paradigmatic jamais essayé d'encoder des flotteurs à distance (pas de Nats) avec ce que Scala offre à cet égard? Faites-moi savoir si vous réussissez.


@MHS n'a jamais essayé (et ne le fera jamais). Mais malgré des limitations, il y a des types dépendants dans Scala et prétendant prétendre que le contraire est faux. Cependant, votre réponse a toujours un sens.


@paradigmatic, je suis sûrement d'accord pour dire que Scala prend en charge les types de dépendants PATH , mais je ne suis pas convaincu que celles-ci vous permettent de coder tout ce type de dépendant général vous permettant d'exprimer. Par exemple, des flotteurs variés. Et je ne suis pas le seul à avoir des doutes, voir les commentaires de SCLV à la réponse que vous avez référencée.


@ PARADADIGMATIQUE Les types dépendants du chemin ne sont pas vraiment quels types de théoriciens signifient quand ils disent des types dépendants. Le point de base est que vous ne peut pas encoder cette notion de flotteur à distance à l'aide de PDTS et peut utiliser DTS. Vous pouvez "soulever" un gros morceau de ce que signifie être un float et le refléter au niveau du type, mais vous pouvez le faire dans des langues avec beaucoup de systèmes de type plus faible, donc je ne suis pas Bien sûr, c'est un critère particulièrement précieux. Tout comme des miles a fait dans sa réponse, je peux appeler une fonction de haskell f :: quelquegadt a -> A un "type PI" et pendant que cela dispose de certaines caractéristiques, ce n'est pas la même chose.


Je ne sais pas pourquoi les gens Scala sont si défensives à propos de ce sujet (c'est absolument en disant que quiconque le contraire est «faux» sans comprendre la théorie de type sous-jacente). Personne ne résolvait la génialité du système de type de Scala. De nombreux types dépendants que les gens aiment toujours faire des trucs fous avec le niveau de type de Haskell, et une grande partie de cela est efficacement des types dépendants, mais vous n'êtes toujours pas en réalité en fonction des valeurs. C'est cool et puissant, mais si vous commencez à parler de "types dépendants limités", c ++ convient également à la facture, et je ne vois pas le point de confusion de la terminologie.


Aurait-il été moins controversé si mon commentaire avait déclaré: «Il convient de noter que même si Scala pourrait exprimer cela, cela viendrait à un coût énorme» sans mentionner le terme DT chargé? La signification est la même, car Scala ne peut pas exprimer un type de flotteur à distance. Agda peut. Appelez la distinction ce que vous voulez.


@paradigmatic J'ai ajouté un paragraphe faisant un argument intuitif Pourquoi les chiffres naturels peuvent être traités, mais les réels ne peuvent pas.


@mhs merci pour l'explication, je vous ai enfin compris que vous aviez le point.


@MHS Je pense que la déclaration la plus précise est de savoir si un type est inductif / données ou non. Les naturels sont inductifs et les Hlistes sont aussi; Les réels ne sont pas, et les flux ne sont pas non plus. Le fait que nous puissions avoir des fonctions de type de type raisonnablement arbitraires suggère que nous pouvons probablement faire des trucs cotinés aussi, cependant. Un codage des rationnels est en tant que paire d'un entier et d'un codage naturel et un codage des réels est fonction des rationnels aux rationnels. Malheureusement, les fonctions de type Scala doivent principalement être écrites en pseudo-cps car vous ne pouvez pas utiliser directement des types.



2
votes

Voici une autre approche en utilisant un Classe implicite em>: xxx pré>

Il nécessite un indice de compilateur d'utiliser la classe implicite, soit en tapant explicitement les Summands explicitement ou En choisissant une méthode qui n'est pas fournie par le flotteur Scala. P>

De cette façon, au moins, les chèques sont centralisés, vous pouvez ainsi l'éteindre, si la performance est un problème. Comme l'a souligné MHS, si cette classe est convertie en une classe de valeur implicite em>, les chèques doivent être supprimés du constructeur. P>

J'ai ajouté @inline annotations, mais je suis Pas sûr, si cela est utile / nécessaire avec classes implicites em>. p>

Enfin, je n'ai eu aucun succès pour ignorer le flotteur Scala "+" avec P>

import scala.{Float => RealFloat}
import scala.Predef.{float2Float => _}
import scala.Predef.{Float2float => _}


0 commentaires

2
votes

Vous pouvez utiliser des classes de valeur comme indiquées par MHS : xxx

Ils doivent être créés à l'aide de la méthode d'usine de l'objet compagnon, qui vérifiera que la gamme est correct: xxx

Cependant, en utilisant des opérations qui ne produira jamais un nombre en dehors de la plage ne nécessiteront pas de contrôle de validité. Par exemple * ou opposé .


2 commentaires

Je ne savais pas que les classes de cas peuvent prolonger NONVAL. Cool!


.. Ainsi MHS obtient la tique, de toute façon la vôtre est assez propre, merci!