Existe-t-il des langages de programmation qui vous permettent de définir l'arithmétique sur les types?

9

Par curiosité, existe-t-il des langages qui vous permettent de définir l'arithmétique sur les types pour en créer de nouveaux? Quelque chose comme:

interface A {
  void a();
  void b();
}

interface B {
  void b();
  void c();
}

interface C = A & B; // has b()
interface D = A | B; // has a(), b() and c()
interface E = (A & B) ^ B; // has c()

Je sais que dans certaines langues, ces idées peuvent être exprimées (c'est-à-dire que Java a List<Comparable & Serializable>pour l'union des interfaces) mais je n'ai jamais entendu parler d'un langage qui prend en charge le type arithmétique. Merci!

Haldean Brown
la source
7
Comment un tel mécanisme serait-il utile?
Robert Harvey
4
Un modèle que j'ai vu beaucoup est une interface qui étend deux autres interfaces et n'ajoute rien (c'est-à-dire CanWriteAndCompare extends Serializable, Comparable {}) et je réfléchissais à la façon de généraliser cela.
Haldean Brown
2
De plus, j'ai rencontré un cas aujourd'hui où j'ai une méthode qui peut prendre un Aou un B, avec deux implémentations qui se ressemblent exactement. Dans la méthode, j'appelle une méthode polymorphe qui peut prendre un Aou un B, donc les implémentations sont les mêmes, mais comme je dois prendre deux types distincts, j'ai besoin de deux implémentations. Ce serait plus facile si je pouvais le faire myMethod(A | B aOrB).
Haldean Brown
1
Oropération peut être émulée par héritage multiple.
utilisateur

Réponses:

4

Tangent ( 0.3 spec ) utilise quelque chose de similaire à cela. (Avertissement: ceci est mon propre petit projet de recherche)

Agit actuellement withcomme un opérateur d'union modélisant l'héritage, bien que le pragmatisme l'ait rendu non commutatif. Une fois que vous introduisez des implémentations de méthodes, une union stricte de méthodes avec le même nom n'est souvent pas ce que vous voulez et impossible de faire de toute façon.

intersectest pris en charge que les modèles saisissent l'inférence pour quelque chose comme foo(T,T)lorsque les paramètres sont différents.

Les compléments étaient intéressants, mais ont conduit à des types partiels qui ne semblaient pas si utiles et / ou gênants à inclure correctement - ne sont donc pas inclus.

Je sais qu'il y a quelques autres langages de recherche que j'ai rencontrés qui avaient quelque chose de similaire, mais je ne m'en souviens pas pour le moment. Le problème principal est que les choses ne sont pas vraiment utiles sans typage structurel, ce qui n'est pas très populaire en soi. L'autre est que vous avez besoin d'une sorte de type (type de types) pour stocker le type construit, ou bien c'est juste un raccourci pour quelque chose qui n'est pas particulièrement idiomatique sans cette capacité. Et c'est beaucoup moins courant que le typage même structurel.

C'est biaisé, et ce n'est pas grand-chose, mais ça y est.

Telastyn
la source
5

Oui, Ceylan est une langue avec des types d'union et d'intersection ad hoc, comme décrit dans ce chapitre de la tournée de Ceylan:

http://ceylon-lang.org/documentation/1.0/tour/types/

C'est incroyable le nombre d'idiomes cool que vous en retirez. Voici un exemple intéressant que j'ai blogué récemment . Et voici une courte présentation où je passe rapidement en revue plusieurs idiomes simples .

Encore mieux, les types d'union / intersection sont le "chaînon manquant" qui fait que l'inférence d'argument de type générique fonctionne vraiment bien à Ceylan, contrairement à d'autres langages qui combinent le sous-type et le polymorphisme paramétrique.

Notez qu'il existe des limitations à ce type de "type arithmétique", comme vous l'avez décrit. Par exemple, vous ne pouvez pas avoir d'opérateur set complément au niveau du type, du moins pas sans introduire l'indécidabilité.

HTH

Gavin King
la source
3

Scala le prend en charge partiellement (intersections mais pas les unions), et tout langage avec sous-typage structurel (je pense que OCaml est un exemple) ou un système de type assez puissant pour émuler cela (Haskell est un classique) aura des "types-as-sets" complets "capacités, au moins dans le fragment de son système de type qui accepte de telles choses (pertinent quand il est émulé ala HList / OOHaskell).

Comme je ne connais pas très bien OCaml, je vais donner la partie de votre exemple qui fonctionne en Scala:

trait A {
  def a(): Unit
  def b(): Unit
}

abstract class B { // just to prove it works with both traits and classes
  def b(): Unit
  def c(): Unit
}

type C = A with B
type D = { def b(): Unit } // not an exact translation, because unions aren't directly available
// type `E` is unrepresentable

Une version pour Haskell dépendrait du système d'enregistrement que vous utilisiez et serait probablement quelque peu maladroite, car elle serait émulée plutôt que prise en charge en mode natif.

Pour autant que je sache, Ceylan a à la fois des types d' intersection et d' union intégrés dans le langage, vous pouvez donc présumer encoder un "xor" de niveau type en termes de ceux-ci.

Flamme de Ptharien
la source
1

Java prend en charge les intersections de types d'interface dans certains contextes, bien qu'il ne permette pas pour autant que je sache de créer des variables de types d'intersection. Les types d'intersection peuvent entrer en jeu, par exemple, lors de l'utilisation de l' ? :opérateur. Si les deuxième et troisième opérandes de cet opérateur sont des interfaces non liées qui héritent des ensembles d'interfaces qui se chevauchent, le résultat de l'opérateur sera l'ensemble d'interfaces communes aux deux.

supercat
la source