Существуют ли языки программирования, которые позволяют задавать арифметику для типов?

9

Из любопытства, есть ли языки, которые позволяют вам задавать арифметику для типов для создания новых типов? Что-то вроде:

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

Я знаю, что в некоторых языках эти идеи могут быть выражены (т. Е. В Java есть List<Comparable & Serializable>объединение интерфейсов), но я никогда не слышал о языке, который поддерживает арифметику типов. Спасибо!

Халдейский коричневый
источник
7
Как бы такой механизм был полезен?
Роберт Харви
4
Шаблон, который я часто видел, - это интерфейс, который расширяет два других интерфейса и ничего не добавляет (т. Е. CanWriteAndCompare extends Serializable, Comparable {}), И я думал о том, как это обобщить.
Haldean Brown
2
Кроме того, сегодня я столкнулся с случаем, когда у меня есть метод, который может принимать a Aили a B, с двумя реализациями, которые выглядят абсолютно одинаково. В методе я вызываю полиморфный метод, который может принимать Aили a B, поэтому реализации одинаковы, но, поскольку мне нужно взять два разных типа, мне нужны две реализации. Это было бы проще, если бы я мог сделать myMethod(A | B aOrB).
Haldean Brown
1
См. Здесь: msdn.microsoft.com/en-us/library/4taxa8t2.aspx
Роберт Харви
1
OrОперация может быть эмулирована множественным наследованием.
пользователь

Ответы:

4

Tangent ( 0.3 spec ) использует что-то похожее на это. (отказ от ответственности: это мой собственный маленький исследовательский проект)

В настоящее время withдействует как оператор объединения, моделирующий наследование, хотя прагматизм сделал его некоммутативным. Как только вы вводите реализации в методы, строгое объединение методов с одинаковыми именами часто оказывается не тем, что вы хотите, и все равно невозможно сделать правильно.

intersectподдерживается, что модели выводят тип для чего-то вроде, foo(T,T)где параметры отличаются.

Дополнения были интересными, но приводили к частичным типам, которые казались не такими полезными и / или проблематичными, чтобы правильно их включать - поэтому они не включены.

Я знаю, что есть несколько других исследовательских языков, с которыми мне приходилось сталкиваться, но сейчас я их не помню. Основная проблема заключается в том, что вещи не очень полезны без структурной типизации, которая сама по себе не очень популярна. Другая причина в том, что вам нужен какой-то вид (тип типов) для хранения созданного типа, или это просто сокращение для чего-то, что не особенно идиоматично без этой возможности. И это гораздо реже, чем даже структурная типизация.

Это предвзято, и это не так много, но это так.

Telastyn
источник
5

Да, Цейлон - это язык со специальными типами объединения и пересечения, как описано в этой главе из тура Цейлона:

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

Удивительно, сколько крутых идиом вы получаете от этого. Вот один интересный пример, который я недавно опубликовал в блоге . И вот короткая презентация, где я быстро приукрашиваю несколько простых идиом .

Более того, типы объединения / пересечения являются «недостающим звеном», благодаря которому вывод аргументов универсального типа действительно работает правильно на Цейлоне, в отличие от других языков, которые сочетают подтип и параметрический полиморфизм.

Обратите внимание, что существуют ограничения для такого рода «арифметики типов», как вы ее описали. Например, вы не можете иметь оператор дополнения множеством на уровне типов, по крайней мере, без введения неразрешимости.

НТН

Гэвин Кинг
источник
3

Scala поддерживает его частично (пересечения, но не объединения), и любой язык со структурным подтипом (я думаю, OCaml является примером) или система типов, достаточно мощная, чтобы эмулировать это (Haskell является классическим), будет иметь полные «типы как наборы» "возможности, по крайней мере, во фрагменте системы типов, которая принимает такие вещи (уместно, когда она эмулируется как HList / OOHaskell).

Поскольку я не очень хорошо знаю OCaml, я приведу ту часть вашего примера, которая работает в 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

Версия для Haskell будет зависеть от используемой вами системы записи и, вероятно, будет несколько неуклюжей, потому что она будет эмулироваться, а не поддерживаться изначально.

Насколько я знаю, в Цейлоне в язык полностью встроены типы пересечений и объединений, так что вы можете предположительно кодировать «xor» на уровне типов в терминах этих.

Пламя Птариена
источник
1

Java поддерживает пересечения типов интерфейсов в некоторых контекстах, хотя, насколько я могу судить, не позволяет создавать переменные типов пересечений. Типы пересечений могут вступать в игру, например, при использовании ? :оператора. Если второй и третий операнды этого оператора являются несвязанными интерфейсами, которые наследуются от перекрывающихся наборов интерфейсов, результатом оператора будет набор интерфейсов, которые являются общими для обоих.

Supercat
источник