Нет, идея именно в том, чтобы сохранить тип полиморфным.
VD>В общем, сделать чтобы компилировался может и можно, но рантайм дотнетный такого не поймет. Это же попытка работать с не воплощенным параметром типов.
Ведь функциональный тип в немерле — это, по сути, класс с виртуальным методом apply, правда? Почему бы не представлять функциональное значение со свободным типом-параметром в виде класса с виртуальным generic методом apply[T]?
VD>К чему этот вопрос? Что-то не хорошее задумал?
Пример на псевдокоде.
Была у нас функция сортировки списка чисел, которая вызывалась из какого-то метода:
Васе понадобилось поправить этот код, чтобы появились функции Reverse (которая переворачивает список задом-наперед) и Shuffle (которая переставляет элементы случайным образом), и чтобы функция Foo могла принимать преобразование, которое она применяет к списку x, в качестве параметра. Вася сделал бранч и написал в нём такой код:
Тем временем Петя тоже поменял этот код: ему понадобилось сортировать в методе Foo не только список чисел, но и список строк. Поэтому он переделал метод Sort в generic метод:
module M
{
Main() : void
{
Foo()
}
Foo() : void
{
def x = [1, 2, 3];
// ...
Sort(x)
// ...def y = ["A", "B", "C"];
// ...
Sort(y)
// ...
}
Sort[T](x : list[T]) : list[T] where T : IComparable[T]
{
// ...
}
}
Тут Вася начинает мёржить бранч со своими изменениями, и получает конфликт, который надо разрезолвить. Поговорив с Петей, он понимает почему метод Sort должен быть generic, и решает, что методы Reverse и Shuffle тоже должны быть generic. Он меняет свой код следующим образом:
Изменения почти удалось смёржить, проблема только в том, что Вася не знает, какую указать сигнатуру у метода Foo. Ему нужно абстрагироваться от передаваемой в метод Foo generic-функции, но так чтобы она не перестала быть generic.
Вася уже собрался городить вспомогательные классы для каждого из методов Sort, Reverse, Shuffle, но вспомнил, что он пишет на замечательном расширяемом языке, и хорошо разбирается в коде компилятора, поэтому он решает реализовать в языке следующую полезную фичу:
module M
{
Main() : void
{
// ...
Foo(Sort);
// ...
Foo(Reverse); // Заметьте, что отсутствие констрейнта у метода Reverse не мешает передать его в метод Foo
// ...
Foo(Shuffle);
}
Foo(transform[T] : list[T] -> list[T] where T : IComparable[T]) : void
{
def x = [1, 2, 3];
// ...
transform(x)
// ...def y = ["A", "B", "C"];
// ...
transform(y)
// ...
}
Sort[T](x : list[T]) : list[T] where T : IComparable[T]
{
// ...
}
Reverse[T](x : list[T]) : list[T]
{
// ...
}
Shuffle(x : list[T]) : list[T]
{
// ...
}
}
Изменения удалось изящно смёржить, а любимый Васин и Петин язык стал ещё мощнее!
Здравствуйте, nikov, Вы писали:
N>Изменения почти удалось смёржить, проблема только в том, что Вася не знает, какую указать сигнатуру у метода Foo. Ему нужно абстрагироваться от передаваемой в метод Foo generic-функции, но так чтобы она не перестала быть generic. N>Вася уже собрался городить вспомогательные классы для каждого из методов Sort, Reverse, Shuffle, но вспомнил, что он пишет на замечательном расширяемом языке, и хорошо разбирается в коде компилятора, поэтому он решает реализовать в языке следующую полезную фичу:
Можно было и без прелюдий . Мы тут люди не дубовые.
N>
N>module M
N>{
N> Main() : void
N> {
N> // ...
N> Foo(Sort);
N> // ...
N> Foo(Reverse); // Заметьте, что отсутствие констрейнта у метода Reverse не мешает передать его в метод Foo
N> // ...
N> Foo(Shuffle);
N> }
N> Foo(transform[T] : list[T] -> list[T] where T : IComparable[T]) : void
N> {
N> def x = [1, 2, 3];
N> // ...
N> transform(x)
N> // ...
N> def y = ["A", "B", "C"];
N> // ...
N> transform(y)
N> // ...
N> }
...
N>}
N>
N>Изменения удалось изящно смёржить, а любимый Васин и Петин язык стал ещё мощнее!
То есть ты это дело предлагаешь переписывать в:
abstract class F
{
public abstract apply[T](_ : T) : T;
}
module Program
{
Foo(transform : F) : void
{
def x = [1, 2, 3];
// ..._ = transform.apply(x);
// ...def y = ["A", "B", "C"];
// ..._ = transform.apply(y);
// ...
}
...
Можно конечно. Вопрос только в том, насколько это часто будет востребовано?
Где-нибудь подобное реализовано? Если, да то какова практика применения?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Список generic функций
От:
Аноним
Дата:
02.06.11 18:28
Оценка:
Здравствуйте, VladD2, Вы писали:
вот это я понимаю под передaчей типа в функцию. Для скриптовых языков это норма.
Здравствуйте, VladD2, Вы писали:
VD>Где-нибудь подобное реализовано?
В Haskell такое есть, называется rank-2 types. Там есть и дальнейшее обобщение этой фичи — rank-N types, позволяющее передавать в качестве параметра полиморфные функции наподобие Foo из моего примера. В Clean есть rank-2 types (rank-N планируются). Не знаю ни одного ООП-языка, где бы это было реализовано (в F# и Scala точно нет).
VD>Если, да то какова практика применения?
Вот это я не знаю наверняка, но мне кажется, что эта фича очень естественная и была бы востребована. Можно поспрашивать у хаскелистов.
Здравствуйте, nikov, Вы писали:
VD>>Если, да то какова практика применения? N>Вот это я не знаю наверняка, но мне кажется, что эта фича очень естественная и была бы востребована.
Откровенно говоря берут меня смутные сомнения по поводу востребованности данной фичи. Одесски ведь явно попытался бы это дело прикруить в Скалу, если он было бы реально надо.
N>Можно поспрашивать у хаскелистов.
Да, надо попробовать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Откровенно говоря берут меня смутные сомнения по поводу востребованности данной фичи. Одесски ведь явно попытался бы это дело прикруить в Скалу, если он было бы реально надо.
Поигрался немножно со Скалой, и у меня появилась идея, как можно записывать rank-N типы с помощью структурных типов. Но там есть проблемы с выводом типов, и оно пока не работает. Я попробую продвинуть эту идею разработчикам. Если будут планы реализовать в Nemerle структурные типы, то я могу поделиться мыслями об их дизайне.
Идея основана на том, что функциональное значение является объектом с методом apply. Базовый синтаксис (наверное, можно подсахарить макросами) я представляю себе примерно таким (Scala-псевдокод):
object A {
def foo[T](x : List[T]) : List[T] = x
def bar(f : { def apply[T](x : List[T]) : List[T] }, x : List[String], y : List[Integer]) { f(x); f(y)}
def qux(x : List[String], y : List[Integer]) { bar(foo(_), x, y) }
}
Здравствуйте, nikov, Вы писали:
N>Если будут планы реализовать в Nemerle структурные типы, то я могу поделиться мыслями об их дизайне.
Желание есть. Я делал пару подходов к дизайну, но ничего путного не вышло. Получается кучча оберточного кода который явно не пройдет даром (в смысле производительности). Так что если есть идеи, то с удовольствием послушаем.
N>Идея основана на том, что функциональное значение является объектом с методом apply. Базовый синтаксис (наверное, можно подсахарить макросами) я представляю себе примерно таким (Scala-псевдокод):
N>
N>object A {
N> def foo[T](x : List[T]) : List[T] = x
N> def bar(f : { def apply[T](x : List[T]) : List[T] }, x : List[String], y : List[Integer]) { f(x); f(y)}
N> def qux(x : List[String], y : List[Integer]) { bar(foo(_), x, y) }
N>}
N>
object — это синглтон?
Мне больше нравится такой синтаксис:
object A
{
def foo[T](x : List[T]) : List[T] = x
def bar(f[T] : List[T] -> List[T], x : List[String], y : List[Integer]) { f(x); f(y)}
def qux(x : List[String], y : List[Integer]) { bar(foo(_), x, y) }
}
Причем тут структурные типы тоже не очень понятно. "f" ведь просто функциональное значение. Как я понимаю в Скале синтаксис вроде f : { def apply[T](x : List[T]) : List[T] } используется для того чтобы в такой параметр можно было передать тип обладающий методом с указанной сигнатурой.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>object — это синглтон?
Да. Наподобие static type, но first-class (может передаваться в качестве значения, экстендить trait-ы и т.д.)
VD>Мне больше нравится такой синтаксис: VD>
VD> def bar(f[T] : List[T] -> List[T], x : List[String], y : List[Integer]) { f(x); f(y)}
VD>
Да, этот синтаксис короче и симпатичнее. Синтаксис, основанный на структурных типах, более общий (позволяет записать не только rank-2, но и произвольные rank-N) и, так сказать, синтаксически "бесплатный" (не требует никаких новых конструкций — по крайней мере, для Scala, где уже есть структурные типы). Краткий синтаксис можно сделать синтаксическим сахаром для частного случая, когда используется rank-2 тип.
VD>Причем тут структурные типы тоже не очень понятно. "f" ведь просто функциональное значение. Как я понимаю в Скале синтаксис вроде f : { def apply[T](x : List[T]) : List[T] } используется для того чтобы в такой параметр можно было передать тип обладающий методом с указанной сигнатурой.
В Скале используется "тотальный" ООП подход: каждое значение — это объект, каждая операция — это вызов метода. Если f — значение функционального типа, то оно также является объектом, и операция f(x) — это всего лишь сокращённая запись вызова метода f.apply(x). Причем это — чистый синтаксический сахар: вызов метода apply у любого объекта obj (не только у значения функционального типа) может быть записан как obj(x). В свете этого, функциональные типы можно понимать просто как частный случай структурных типов.
Здравствуйте, nikov, Вы писали:
N> В свете этого, функциональные типы можно понимать просто как частный случай структурных типов.
Например, в Скала такой код успешно компилируется:
object A {
def apply(x : String) : String = x
def f : String => String = A(_) // к сожалению, частичное применение надо указывать явноdef s : { def apply(x : String) : String } = f
}
Будь моя воля, я бы сделал функциональный тип просто синтаксическим сахаром для структурного с методом apply, чтобы можно было написать так:
object A {
def apply(x : String) : String = x
def s : { def apply(x : String) : String } = A
def f : String => String = A
def g : String => String = s
}
(надеюсь, никто не обидится за маленькое злоупотребление тегами )
Здравствуйте, nikov, Вы писали:
N>Если будут планы реализовать в Nemerle структурные типы, то я могу поделиться мыслями об их дизайне.
Планы есть, но как реализовать их без тяжелых рантайм проверок непонятно.
f(x : object) : void
{
def y = x :> classwith { apply() : void; };
y.apply();
}
Единственная идея у меня — замена структурного типа на интерфейс и генерация классов проксей для каждого встреченного типа в рантайме. С выносом в компайлтайм проксей для тех типов которые мы можем узнать при анализе кода.
Здравствуйте, Ziaw, Вы писали:
Z>Единственная идея у меня — замена структурного типа на интерфейс и генерация классов проксей для каждого встреченного типа в рантайме. С выносом в компайлтайм проксей для тех типов которые мы можем узнать при анализе кода.
Тут встают проблемы ссылочной эквивалентности. Ссылка на прокси не будет равна ссылке на объект.
Здравствуйте, hardcase, Вы писали:
Z>>Единственная идея у меня — замена структурного типа на интерфейс и генерация классов проксей для каждого встреченного типа в рантайме. С выносом в компайлтайм проксей для тех типов которые мы можем узнать при анализе кода.
H>Тут встают проблемы ссылочной эквивалентности. Ссылка на прокси не будет равна ссылке на объект.
Здравствуйте, Ziaw, Вы писали:
Z>>>Единственная идея у меня — замена структурного типа на интерфейс и генерация классов проксей для каждого встреченного типа в рантайме. С выносом в компайлтайм проксей для тех типов которые мы можем узнать при анализе кода.
H>>Тут встают проблемы ссылочной эквивалентности. Ссылка на прокси не будет равна ссылке на объект.
Z>Можно проксировать методы.
Будет еще медленнее. Возможно выходом будет попытаться попробовать воспользоваться структурной эквивалентностью 4-го дотнета. Но она доступна только для интерфейсов и структур.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Будет еще медленнее. Возможно выходом будет попытаться попробовать воспользоваться структурной эквивалентностью 4-го дотнета. Но она доступна только для интерфейсов и структур.
Чем медленнее? Дополнительный метод который вызывает нужный нам. С прокси объектом ровно тот же сценарий.