Scala: более качественные, открытые и дикие карты в Java, С#, Scala и С++

Я программировал на С#, но был разочарован ограничениями его системы типов. Одна из первых вещей, которые я узнал о Scala, заключалась в том, что Scala имеет более высокие сородичи. Но даже после того, как я просмотрел ряд статей, записей в блогах и вопросов, я до сих пор не был уверен, что такое более высокие сородичи. В любом случае, я написал код Scala, который скомпилирован отлично, Использует ли этот фрагмент более высокие типы?

abstract class Descrip [T <: DTypes, GeomT[_ <: DTypes] <: GeomBase[_]](newGeom: NewGeom[GeomT])
{
  type GeomType = GeomT[T]
  val geomM: GeomT[T] = newGeom.apply[T]()  
}

И тогда я подумал, что, возможно, я уже использую более высокие сородичи. Насколько я понимаю, я был, но тогда, как я теперь понимаю, я уже с удовольствием использовал более высокие типы типов на С#, прежде чем я даже слышал о Scala. Использует ли этот снайпер более высокий тип?

namespace ConsoleApplication3
{
    class Class1<T>
    {
        List<List<T>> listlist;
    }
}

Итак, чтобы предотвратить дальнейшую путаницу, я подумал, что было бы полезно уточнить для каждого из Java, С# и Scala то, что они позволяют в терминах более высоких типов, диких карт и использования открытых/частично открытых типов. Поскольку ключевое различие между С# и Scala, похоже, заключается в том, что Scala позволяет использовать дикие карты и открытые типы, где С# не имеет wild card и требует, чтобы все общие типы были закрыты перед использованием. Я знаю, что они разные, но я думаю, было бы полезно связать существование этих функций с их эквивалентом в С++ Templates.

Итак, правильнее?. Эта таблица была исправлена ​​для ответа Алексея

Lang:   Higher-kind Wild-card Open-types

Scala    yes         yes       yes

C#       no          no        no

Java     no          yes       no

C++      yes         yes       yes

Ответ 1

Это более высокий тип типа:

Нет. Тип более высокого типа похож на

class Class1<T>
{
    T<String> foo; // won't compile in actual C#
}

т.е. общий тип, параметры которого должны быть общими. Обратите внимание, что в этом примере Class1<IList> должен компилироваться, но Class1<String> или Class1<IDictionary> не должен.

Ответ 2

Кажется, вам нужно понять, что такое более высокие типы, и почему они полезны.

Рассмотрим следующие интерфейсы (Java, F<X,Y>, используемые как замена замка):

interface ListFun {
   public <A,B> List<B> fmap(F<A,B> fn, List<A> list);
}

interface SetFun {
   public <A,B> Set<B> fmap(F<A,B> fn, Set<A> set);
}

Интерфейсы выглядят полезными, поскольку они определяют своего рода "трансформацию" для коллекций (это называется "функтором" ). Но они очень похожи на дублирование кода. Но вы не можете написать "унифицированный" интерфейс, ни на Java, ни на С#.

Как это должно выглядеть? У вас возникнет соблазн написать что-то вроде

interface Fun<X> {
   public <A,B> X<B> fmap(F<A,B> fn, X<A> col);
}

class ListFun implements Fun<List> {...}

Но X<A> не допускается в Java или С#, если X не является фиксированным типом типа List, а параметром типа. Но если эта абстракция разрешена каким-то образом (например, в Scala или Haskell), у вас более высокие типы типов (или "полиморфизм более высокого порядка", для этой терминологии все еще мрачная). Вот черта Scala и реализация:

trait Fun[X[_]] {
  def fmap[A,B](fn: A => B, col:X[A]):X[B]
}

class ListFun extends Fun[List]{
  def fmap[A,B](fn: A => B, list: List[A]) = list.map(fn)
}

Это основная идея. Обычно вам не нужно это слишком часто, но когда вам это нужно, это может быть невероятно полезно.