Esistono linguaggi di programmazione che ti consentono di impostare l'aritmetica sui tipi?


9

Per curiosità, ci sono lingue che ti consentono di impostare l'aritmetica sui tipi per crearne di nuovi? Qualcosa di simile a:

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()

So che in alcune lingue queste idee possono essere espresse (cioè Java ha List<Comparable & Serializable>per l'unione delle interfacce) ma non ho mai sentito parlare di un linguaggio che supporti l'aritmetica dei tipi. Grazie!


7
Come sarebbe utile tale meccanismo?
Robert Harvey,

4
Un modello che ho visto molto è un'interfaccia che estende altre due interfacce e non aggiunge nulla (cioè, CanWriteAndCompare extends Serializable, Comparable {}) e stavo pensando a come generalizzare questo.
Haldean Brown,

2
Inoltre, mi sono imbattuto in un caso oggi in cui ho un metodo che può prendere un Ao un B, con due implementazioni che sembrano esattamente uguali. Nel metodo sto chiamando un metodo polimorfico che può prendere un Ao un B, quindi le implementazioni sono le stesse, ma poiché devo prendere due tipi distinti ho bisogno di due implementazioni. Sarebbe più facile se potessi farlo myMethod(A | B aOrB).
Haldean Brown,


1
Orl'operazione può essere emulata per eredità multipla.
utente

Risposte:


4

Tangent ( 0.3 spec ) usa qualcosa di simile a questo. (disclaimer: questo è il mio piccolo progetto di ricerca)

Attualmente withagisce come operatore sindacale modellando l'eredità, sebbene il pragmatismo non l'abbia resa commutativa. Una volta introdotte le implementazioni ai metodi, una stretta unione di metodi con lo stesso nome spesso non è ciò che si desidera e comunque impossibile fare correttamente.

intersectè supportato il fatto che i modelli digitino l'inferenza per qualcosa come foo(T,T)dove i parametri sono diversi.

I complementi erano interessanti, ma hanno portato a tipi parziali che non sembravano così utili e / o fastidiosi da includere correttamente, quindi non sono inclusi.

So che ci sono alcuni altri linguaggi di ricerca che ho incontrato che avevano qualcosa di simile, ma al momento non li ricordo. Il problema principale è che le cose non sono davvero utili senza la digitazione strutturale, che non è terribilmente popolare in sé. L'altro è che hai bisogno di una sorta di tipo (tipo di tipi) per memorizzare il tipo costruito, oppure è solo una scorciatoia per qualcosa che non è particolarmente idiomatico senza quella capacità. E questo è molto meno comune della tipizzazione strutturale.

È di parte, e non è molto, ma è così.


5

Sì, Ceylon è una lingua con tipi di unione e intersezione ad hoc, come descritto in questo capitolo del tour di Ceylon:

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

È incredibile il numero di idiomi fantastici che ottieni da questo. Ecco un esempio interessante che ho blog di recente . Ed ecco una breve presentazione in cui ripasso rapidamente diversi semplici modi di dire .

Ancora meglio, i tipi di unione / intersezione sono il "collegamento mancante" che fa in modo che l'inferenza di argomenti di tipo generico funzioni proprio nel Ceylon rispetto ad altre lingue che combinano sottotipo e polimorfismo parametrico.

Nota che ci sono limitazioni a questo tipo di "tipo aritmetico", come l'hai descritto. Ad esempio, non è possibile avere un operatore di complemento impostato a livello di tipo, almeno non senza introdurre indecidibilità.

HTH


3

Scala lo supporta parzialmente (intersezioni ma non sindacati) e qualsiasi linguaggio con sottotipizzazione strutturale (penso che OCaml sia un esempio) o un sistema di tipi abbastanza potente da emulare che (Haskell è un classico) avrà "tipi-come-insiemi completi "capacità, almeno all'interno del frammento del suo sistema di tipi che accetta tali cose (rilevanti quando è emulato da HList / OOHaskell).

Dato che non conosco molto bene OCaml, darò la parte del tuo esempio che funziona in 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

Una versione per Haskell dipenderebbe dal sistema di registrazione che stavi usando e probabilmente sarebbe alquanto goffa, perché sarebbe emulata piuttosto che supportata nativamente.

Per quanto ne so, Ceylon ha entrambi i tipi di intersezione e unione integrati nella lingua in piena potenza, quindi si può presumere codificare un "xor" a livello di tipo in termini di quelli.


1

Java supporta le intersezioni dei tipi di interfaccia in alcuni contesti, anche se non posso dire che consenta la creazione di variabili di tipi di intersezione. I tipi di intersezione possono entrare in gioco, ad esempio, quando si utilizza l' ? :operatore. Se il secondo e il terzo operando di quell'operatore sono interfacce non correlate che ereditano da insiemi di interfacce sovrapposte, il risultato dell'operatore sarà l'insieme di interfacce comuni a entrambi.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.