10
votes

Signature de type Haskell pour les entiers

disons que je veux écrire une fonction pour décider si un numéro entier donné est prime, que Signature de type forte> dois-je utiliser?

  isPrime :: (Integral a) => a -> Bool


0 commentaires

3 Réponses :


11
votes

Le type int -> bool signifie que votre fonction fonctionne sur des valeurs de type int , qui sont des entiers limités de taille (la taille maximale étant, je crois, machine -dépendant).

Le type (intégral A) => a -> bool signifie que votre fonction fonctionne sur des valeurs de tout type qui a une instance du intégrale < / Code> Classe de type - c'est-à-dire des types qui se comportent comme des entiers d'une manière particulière. La principale raison de choisir cela sur un type concret consiste à créer une fonction plus générale.

Les formulaires génériques utilisant intégrale ont tendance à être très utiles lorsque vous devez travailler avec des types d'entier dans d'autres contextes - un bon exemple d'être des endroits où la bibliothèque standard échoue > faire, par exemple Fonctions telles que Replicat :: int -> a -> [a] . Code qui fonctionne sur un type de type entier spécifique à ses propres fins qui souhaite utiliser ce type avec Repliquer doivent donc convertir en int d'abord, ou importer générique à partir de data.list .

Ce que vous voudrez peut-être envisager dans votre cas est à la place du type entier , qui représente des entiers de taille arbitraire. Puisque votre objectif principal est le calcul, il existe moins de valeur pour supporter des types d'intégrale arbitraires.

Si la mémoire me sert, les seules instances de intégrale dans la bibliothèque standard sont int et integer de toute façon. ( EDIT : Comme Hammar me rappelle dans les commentaires, il existe également des instances pour les types de taille fixe dans data.int et data.word . Il existe également des types étrangers tels que cint mais je ne tiens pas compte des personnes intentionnellement.)


7 commentaires

Il existe également les taille fixe dans data.int et data.word .


@hammar: Ah, droite! J'ai oublié ceux qui font réellement partie des bibliothèques standard, merci.


Troisième option: Définir une classe de caractères Class Hasprimes A Où Isprime :: A -> Bool vous permettrait de définir un algorithme de primalité différent pour chaque type. Vous pouvez même définir une instance par défaut intégrale A => HASPRimes A Où ... avec un algorithme général. L'avantage est que si vous avez eu un algorithme plus efficace pour un type particulier, vous pouvez également l'utiliser, de sorte que ce serait le meilleur des deux mondes.


@rampion L'instance par défaut est imo une mauvaise idée, comme cela nécessiterait chevauchant des contextes . La classe est une bonne idée.


@Danielfischer: Je suppose que instance hasprimes entier et isintationgalPrime :: Integral A => A -> Bool; isintgralprime = isprime. totinteger suffirait plutôt qu'une instance par défaut.


@Rampion Oui, je pense que cela ferait bien.


@DANIELFISCHER: Ou si vous vouliez restreindre hasprimes à intégral Types, vous pouvez utiliser une implémentation par défaut dans la classe elle-même: classe intégrale A => haleprimes a où isprime :: a -> bool; isprime = isIntegerprime. totinteger



1
votes

De nombreux tests de primalité sont probabilistes et ont besoin de nombres aléatoires, donc au moins au niveau le plus bas, ils auraient une signature de type comme celle-ci: xxx

une contrainte intégrale semble raisonnable, parce que vous faites généralement Pas besoin d'un type de béton, mais uniquement des opérations telles que REM .


1 commentaires

Eh bien, un test probabiliste aurait besoin d'un type de retour monadique: semble-être :: (intégrale a) => a -> [a] -> io bool



4
votes

Je recommanderais la signature xxx

une signature isprime :: int -> bool exclurait des tests rapides pour les nombres de largish, car ces tests débordaient souvent alors (Techniquement, c'est aussi vrai de entier , au moins dans la version fournie par INTEGER-GMP , mais vous serez probablement hors de mémoire long Avant cela importe, nous pouvons donc maintenir la fiction d'un type INEGER Integer ).

Un type isprime :: Integral A => A -> BOOL serait un mensonge avec une implémentation réalisable. On pourrait avoir une instance de intégrale pour une modélisation de type z [sqrt (2)] (bien que pour un tel type totinteger serait infidèle) , pour un tel type, 2 ne serait pas un premier, comment détecterait-on qu'avec un test générique?

ou envisager des types finis Modélisation d'une bague de facteur z / (n) . Une instance ord pour ces types serait incompatible avec l'arithmétique, mais nous avons déjà cela pour int , etc., par exemple, dans z (6) = {0 , 1,2,3,4,5} , le Primes serait 2 , 3 et 4 (Notez que rien d'entre eux n'est irréductible , 2 = 4 * 2, 3 = 3 * 3, 4 = 2 * 2).

Donc, le seul test significatif et réalisable est: "Est-ce une prime rationnelle (ou naturelle) dont la valeur se trouve dans la gamme du type?" . Qui est capturé (aussi bon que possible sans sacrifier trop de vitesse) dans le type isprime :: entier -> bool , pour être combiné avec un TOINTEGER le cas échéant.


4 commentaires

Ce n'est pas à propos de ma question mais pourquoi 5 est-il un premier depuis 5 est non-zéro non-unité et 5 | 1 * 5 => 5 | 5 ; aussi pourquoi 2 et 3 ne sont pas irréductibles


5 est une unité, 5 * 5 = 1 . Et nous pouvons écrire 2 = 4 * 2 , ni 4 ni 2 être une unité, et 3 = 3 * 3 , ni 3 ni 3 être une unité, donc 2 et 3 sont réductibles. D'autre part, si 2 divise a * b alors 2 doit déjà diviser A ou B (qui est hérité de z), donc 2 est une principale (alternativement, (z / 6) / 2 ~ z / 3 , la bague de facteur de z / (6) par l'idéal généré par 2 est le champ z / (3) , en particulier un domaine intégral). Similaire pour 3.


Je pense que je ferais mieux de me tourner vers un livre sur l'algèbre abstrait plutôt que de vous déranger avec des concepts de base ici; Vous pensez donc que nous ne pouvons pas traiter de telles choses avec Haskell ou avec d'autres langages de programmation?


Oh, ces concepts ne sont pas si basiques. Mais un bon livre est certainement un meilleur moyen de l'apprendre - si vous voulez - que l'espace limité dans les commentaires. Traiter avec de telles choses n'est pas trivial, la classe intégrale n'est pas la bonne façon pour cela, mais la remparte proposé un hasprimes classe dans les commentaires pour C.A. La réponse de McCann, alors chaque instance serait responsable du bon comportement dans ce cas. Notez que les nombres premiers dans les anneaux avec des diviseurs de zéro comme z / (6) ne sont pas très intéressants. Mais l'autre exemple ou des anneaux polynomiaux sont intéressants et ne correspondent pas au corset intégrale .