Czy istnieją języki programowania, które pozwalają ustawić arytmetykę na typach?

9

Z ciekawości, czy istnieją języki, które pozwalają ci ustawiać arytmetykę typów, aby tworzyć nowe typy? Coś jak:

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

Wiem, że w niektórych językach można wyrażać te idee (tj. Java ma List<Comparable & Serializable>na celu połączenie interfejsów), ale nigdy nie słyszałem o języku, który obsługuje arytmetykę typów. Dzięki!

Haldean Brown
źródło
7
Jak przydatny byłby taki mechanizm?
Robert Harvey
4
Wzorzec, który często widziałem, to interfejs, który rozszerza dwa inne interfejsy i niczego nie dodaje (tj. CanWriteAndCompare extends Serializable, Comparable {}) I zastanawiałem się, jak to uogólnić.
Haldean Brown,
2
Ponadto spotkałem się dzisiaj z przypadkiem, w którym mam metodę, która może przyjąć wartość Aa lub a B, z dwiema implementacjami, które wyglądają dokładnie tak samo. W metodzie nazywam metodę polimorficzną, która może przyjąć wartość Aa lub a B, więc implementacje są takie same, ale ponieważ muszę wziąć dwa różne typy, potrzebuję dwóch implementacji. Byłoby łatwiej, gdybym mógł myMethod(A | B aOrB).
Haldean Brown,
1
Zobacz tutaj: msdn.microsoft.com/en-us/library/4taxa8t2.aspx
Robert Harvey
1
Oroperacja może być emulowana przez wielokrotne dziedziczenie.
użytkownik

Odpowiedzi:

4

Tangent ( specyfikacja 0.3 ) używa czegoś podobnego do tego. (zrzeczenie się: to mój mały projekt badawczy)

Obecnie withdziała jako operator modelowania dziedziczenia przez związki, chociaż pragmatyzm sprawił, że nie jest on przemienny. Po wprowadzeniu implementacji metod ścisłe połączenie metod o tej samej nazwie często nie jest tym, czego chcesz, i i tak nie można tego zrobić właściwie.

intersectobsługiwane jest wnioskowanie o typach modeli dla czegoś takiego, foo(T,T)gdzie parametry są różne.

Uzupełnienia były interesujące, ale doprowadziły do ​​częściowych typów, które wydawały się nie tak przydatne i / lub kłopotliwe do prawidłowego włączenia - więc nie zostały uwzględnione.

Wiem, że natknąłem się na kilka innych języków badawczych, które miały coś podobnego, ale w tej chwili ich nie pamiętam. Głównym problemem jest to, że rzeczy nie są tak naprawdę przydatne bez strukturalnego pisania, co samo w sobie nie jest zbyt popularne. Drugim jest to, że potrzebujesz jakiegoś rodzaju (rodzaju typów) do przechowywania skonstruowanego typu, w przeciwnym razie jest to po prostu skrót dla czegoś, co nie jest szczególnie idiomatyczne bez tej możliwości. A to znacznie mniej powszechne niż nawet pisanie strukturalne.

Jest tendencyjny i niewiele, ale jest.

Telastyn
źródło
5

Tak, Cejlon jest językiem z typami połączeń i skrzyżowań ad hoc, jak opisano w tym rozdziale z wycieczki po Cejlonie:

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

To niesamowita liczba fajnych idiomów, które z tego czerpiesz. Oto jeden interesujący przykład, który niedawno napisałem na blogu . A oto krótka prezentacja, w której szybko przeglądam kilka prostych idiomów .

Co więcej, typy unii / przecięcia są „brakującym ogniwem”, które sprawia, że ​​wnioskowanie argumentów typu ogólnego naprawdę działa poprawnie na Cejlonie, w przeciwieństwie do innych języków, które łączą podtyp i polimorfizm parametryczny.

Zauważ, że istnieją ograniczenia tego rodzaju „arytmetyki typu”, jak to opisałeś. Na przykład nie można mieć ustawionego operatora dopełniania na poziomie typu, przynajmniej nie bez wprowadzenia nierozstrzygalności.

HTH

Gavin King
źródło
3

Scala obsługuje go częściowo (przecięcia, ale nie związki), a każdy język z podtypami strukturalnymi (myślę, że OCaml jest przykładem) lub system typów wystarczająco mocny, aby go naśladować (Haskell jest klasycznym), będzie miał pełne „typy-jako-zestawy "możliwości, przynajmniej w obrębie fragmentu systemu typów, który akceptuje takie rzeczy (istotne, gdy jest emulowany ala HList / OOHaskell).

Ponieważ nie znam zbyt dobrze OCaml, podam część twojego przykładu, która działa w Scali:

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

Wersja dla Haskell zależałaby od używanego systemu nagrań i prawdopodobnie byłaby nieco niezręczna, ponieważ byłaby emulowana, a nie natywnie obsługiwana.

O ile mi wiadomo, Ceylon ma wbudowane w język zarówno typy przecinania się, jak i unii, więc można przypuszczać, że można je zakodować na poziomie typu „xor”.

Płomień Pthariena
źródło
1

Java obsługuje skrzyżowania typów interfejsów w niektórych kontekstach, choć nie jest to tak dalece, jak mogę stwierdzić, pozwalając na tworzenie zmiennych typów skrzyżowań. Rodzaje skrzyżowań mogą wchodzić w grę, na przykład podczas korzystania z ? :operatora. Jeśli drugi i trzeci operand tego operatora są niepowiązanymi interfejsami, które dziedziczą po nakładających się zestawach interfejsów, wynikiem operatora będzie zestaw interfejsów, które są wspólne dla obu.

supercat
źródło