Здравствуйте, ecinunice, Вы писали:
E>Сводится ли частичное применение к синтаксическому сахару или есть другие приемущества? Если другие приемущества есть — можно привести пример?
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, ecinunice, Вы писали:
E>>Сводится ли частичное применение к синтаксическому сахару или есть другие приемущества? Если другие приемущества есть — можно привести пример?
К>А о чём конкретно речь? О карринге?
Коллегам был продемонстрирован пример частичного применения на Nemerle, посмотрев на него они сказали, что не видят существенной разницы между
def f( x, y) {
...
}
def g = f( x, _)
и
def f( x, y) {
...
}
def g ( y ) {
f( x, y)
}
Вот и возник вопрос — есть ли такие особенности частичного применения, которые не нельзя приклеить ярлык синтаксического сахара (конкретный язык не важен).
Здравствуйте, ecinunice, Вы писали:
E>Сводится ли частичное применение к синтаксическому сахару или есть другие приемущества? Если другие приемущества есть — можно привести пример?
Чистый сахор, но приемущества есть. Значительно более читабельно получается. Скажем если нам нужно куда-то передать фунцию сравнения, то вместо:
def result = lst.Filter((x, y) => x == y);
Можно писать:
def result = lst.Filter(_ == _);
Соответственно упращаются и остальные случаи применения, а код становится понятнее.
ЗЫ
Вообще частичное прменение есть пока что только в Немерле. Так что вопрос можно было задавать в его форуме.
В языках ML-но группы аналогом является карринг.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Чистый сахор, но приемущества есть. Значительно более читабельно получается. VD>Соответственно упращаются и остальные случаи применения, а код становится понятнее.
Тут главный вопрос — не переборщить с этими по сути анонимными функциями, иначе понятность может ухудшиться.
Здравствуйте, VladD2, Вы писали:
VD>В языках ML-но группы аналогом является карринг.
Почему, на Ваш взгляд, в N ввели свой термин, а не воспользовались устоявшимся?
PS: Меня смущает слово применение — оно наводит на мысль, что вот такой тест
mutable i = 0;
def f (a, b){
i = i + 1; // частично применилось один раз при создании g
a + b
}
def g = f (10, _ );
WriteLine(g ( 1 ));
WriteLine($"i: $i");
WriteLine(g ( 1 ));
WriteLine($"i: $i");
должен выводить
11
i: 1
11
i: 1
a выводит, естественно,
11
i: 1
11
i: 2
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, ecinunice, Вы писали:
E>>PS: Меня смущает слово применение — оно наводит на мысль, что вот такой тест E>>
E>> mutable i = 0;
К>[cut]
E>>
К>Mutable — зло, как раз тут у тебя проявляется то, что он делает reasoning по поводу кода неприменимым.
Т.е. можно предоставить пример, в котором reasoning кода будет применимым? Можно линк или сам пример?
Здравствуйте, ecinunice, Вы писали:
E>Т.е. можно предоставить пример, в котором reasoning кода будет применимым? Можно линк или сам пример?
Вообще это обширная тема и я не уверен, что очень хорошо в ней ориентируюсь, глянь к примеру долклад Дениса о бесплатных теоремах
Кроме частичного применения есть частичные вычисления, вот глянь книжку, там суть в том, что можно часть программы предвычислить до её выполнения. Фактически статическая типизация является частным случаем, там по сути выкидываются проверки типов, в отличие от языков с динамической типизацией.
Здравствуйте, VladD2, Вы писали:
VD>Чистый сахор, но приемущества есть. Значительно более читабельно получается. Скажем если нам нужно куда-то передать фунцию сравнения, то вместо: VD>
VD>def result = lst.Filter((x, y) => x == y);
VD>
VD>Можно писать: VD>
VD>def result = lst.Filter(_ == _);
VD>
VD>Соответственно упращаются и остальные случаи применения, а код становится понятнее.
Здравствуйте, Lloyd, Вы писали:
L>Лично мне — нет. С лямбда-синтаксисом еще куда ни шло...
А в чем разница.
Filter ждёт бинарного предиката, он туда и засовывается: _==_. Подчёркивания замещают аргументы. Я Nemerle не знаю, но мне так вполне понятно. Функциональщина же нынче не дикая экзотика.
Здравствуйте, VladD2, Вы писали:
VD>Вообще частичное прменение есть пока что только в Немерле. Так что вопрос можно было задавать в его форуме. VD>В языках ML-но группы аналогом является карринг.
В Хаскелле частичное применение — устойчивый термин, и стандартный ход в программировании. Там просто вообще не надо даже _ (подчеркивание) для "неприменённых" аргументов указывать, поскольку арность идентификатора не перегружается.
А карринг в Хаскелле (и вообще в ML) это преобразование функции от кортежа в ФВП одного аргумента
-- было
f :: (a, b) -> c
-- стало
(curry f) :: a -> (b -> c)
Получившаяся curry f допускает частичное применение по-хаскеллски: применили к x типа a — получили (curry f x) :: b -> c. Например
-- функция от кортежа
sumTuple :: (Integer, Integer) -> Integer
sumTuple (x,y) = x + y
-- каррируем
sum :: Integer -> Integer -> Integer
sum = curry sumTuple
-- применяем частично
add42 :: Integer -> Integer
add42 = sum 42
-- add42 5 вернёт 47
Другое дело, что в Хаскелле почти все функции и так уже каррированные, поэтому их вполне себе частично применяют за глаза и за уши.
Здравствуйте, deniok, Вы писали:
D>А карринг в Хаскелле (и вообще в ML) это преобразование функции от кортежа в ФВП одного аргумента
В Окамле еще страшнее, есть только функции от одного аргумента, а функции от многих аргументов чистый сахар например функция от двух аргументов это реально функция от первого аргумента выдающая как результат функцию (каррированую) к которой можно применить второй аргумент:
# let f x y = x + y;;
val f : int -> int -> int = <fun>
# f 1;;
- : int -> int = <fun>
Здравствуйте, ecinunice, Вы писали:
E>Здравствуйте, Курилка, Вы писали:
К>>Здравствуйте, ecinunice, Вы писали:
E>>>Сводится ли частичное применение к синтаксическому сахару или есть другие приемущества? Если другие приемущества есть — можно привести пример?
К>>А о чём конкретно речь? О карринге?
E>Коллегам был продемонстрирован пример частичного применения на Nemerle, посмотрев на него они сказали, что не видят существенной разницы между E>
E>def f( x, y) {
E> ...
E>}
E>def g = f( x, _)
E>
E>и
E>
E>def f( x, y) {
E> ...
E>}
E>def g ( y ) {
E> f( x, y)
E>}
E>
E>Вот и возник вопрос — есть ли такие особенности частичного применения, которые не нельзя приклеить ярлык синтаксического сахара (конкретный язык не важен).
Если f — фиксирована, то разницы, в общем-то, нет. А вот если f является переменной, то таки разница есть. На втором шарпе идея g будет выглядеть примерно так:
public delegate void OneArgument<T>(T arg);
public delegate void TwoArguments<T1, T2>(T1 arg1, T2 arg2);
public OneArgument<T2> g(TwoArguments<T1, T2> f, T1 arg1)
{
return delegate(T2 arg2) { return input(arg1, arg2); };
}
Как видим, это немножечко более громоздко, чем прямая поддержка частичного применения в синтаксисе.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, ecinunice, Вы писали:
E>Вот и возник вопрос — есть ли такие особенности частичного применения, которые не нельзя приклеить ярлык синтаксического сахара (конкретный язык не важен).
Некоторые склонны разделять понятия синтаксического сахара и языковой абстракции. Хотя точную грань провести трудно, частичное применение — скорее второе.
Здравствуйте, Трурль, Вы писали:
Т>Некоторые склонны разделять понятия синтаксического сахара и языковой абстракции. Хотя точную грань провести трудно, частичное применение — скорее второе.
В том же окамле или хаскеле наоборот получается что функция с несколькими аргументами это синтаксический сахар для функции с одним аргументом + частичное применение.
Здравствуйте, deniok, Вы писали:
D>В Хаскелле частичное применение — устойчивый термин,
ОК, хотч я его что-то не слышал. Ну, да я не хаскелемен.
D> и стандартный ход в программировании.
Это в какм? Или у нас уже Хаскель и Немерле стали мэйнстримом?
D> Там просто вообще не надо даже _ (подчеркивание) для "неприменённых" аргументов указывать, поскольку арность идентификатора не перегружается.
Это значения не имеет. Это особенности хаскеля.
Вот только в Хаскеле этот самый Partial_application и реализуется за счет карринга. Так что тут ты, как я понимаю, не прав.
D>А карринг в Хаскелле (и вообще в ML) это преобразование функции от кортежа в ФВП одного аргумента
Вот про кортеж ты вопро спорный.
Белиберда с кортежами в Хаскеле получается просто потму, что в нем нет привычного скобочного синтаксиса.
По этому в нем функции получают не список аргументов и возвращают значение (как в привычных языка), а фукнция получает одни аргумет который может быть фунцкцией, ну, а много аргументов трактуются как копозиция функций каждая из которых получает по одному. Ну, и как я понимаю далее диет простая эвивалетность:
X * Y -> Z = X -> Y -> Z
для простых смертный это вообще не ястно, но вот как раз частичное применение на это деле получается как последовательного замыкание.
Собственно в раделе Definition в Википедии (по твоей ссылке) это и демонстрируется.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, deniok, Вы писали:
D>> и стандартный ход в программировании.
VD>Это в какм? Или у нас уже Хаскель и Немерле стали мэйнстримом?
В Хаскелле имелось ввиду.
VD>Вот только в Хаскеле этот самый Partial_application и реализуется за счет карринга. Так что тут ты, как я понимаю, не прав.
Неа. Карринг легко реализуется средствами языка (см. в конце поста), а возможность Partial application — это как раз одно из следствий ленивости, то есть нормального порядка редукций при вычислении. Недопримененный терм сохраняется как thunk, который используется при окончательном применении.
D>>А карринг в Хаскелле (и вообще в ML) это преобразование функции от кортежа в ФВП одного аргумента
VD>Вот про кортеж ты вопро спорный. VD>Белиберда с кортежами в Хаскеле получается просто потму, что в нем нет привычного скобочного синтаксиса.
Есть. Кортежи как раз позволяют записывать вызовы идентично этому синтаксису.
Кортеж из типов X и Y, сам по себе, и есть в математической нотации прямое произведение типов — X*Y. А каррирование — это преобразование функции из традиционного (с прямым произведением) вида в вид, пригодный для последовательного частичного применения.
Можно и в обратную сторону превратить все функции Хаскелла в скобочные.
-- берём, например, map ...
map :: (a -> b) -> [a] -> [b]
-- ... и "декаррируем" его, приводя к скобочной форме (кортежной, на самом деле)
mapWithBrackets = uncurry map
Здравствуйте, Трурль, Вы писали:
Т>Некоторые склонны разделять понятия синтаксического сахара и языковой абстракции. Хотя точную грань провести трудно, частичное применение — скорее второе.
А эти некоторые могут описать алгоритм проведения грани?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, FR, Вы писали:
FR>В том же окамле или хаскеле наоборот получается что функция с несколькими аргументами это синтаксический сахар для функции с одним аргументом + частичное применение.
Это потому что некоторые фичи можно выразить друг через друга. Классический пример — циклы. И что для чего в таком случа является сахаром лично я сказать не решусь.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>А эти некоторые могут описать алгоритм проведения грани?
Алгоритм — вряд ли. Но можно придумать эмпирическое правило. Если все сводится чисто к синтаксическим преобразованиям, то это синтаксический сахар (или иногда синтаксический крысиный яд). Если же в дело вмешивается семантика, возникают новые понятия, то это уже абстрация.
Например, for — чистый сахар, а foreach — нет. И даже for в паскале нельзя считать просто сахаром.
Конечно, все это имеет смысл, если мы выделяем некоторое ядро языка. Собственно, термин возник, когда Ландин обозвал let синтаксическим сахаром для лямбды.
Здравствуйте, FR, Вы писали:
FR>В том же окамле или хаскеле наоборот получается что функция с несколькими аргументами это синтаксический сахар для функции с одним аргументом + частичное применение.
В окамле и хаскеле нет функций с несколькими аргументами и нет смысла говорить о частичном применении.
Точнее, говорить то можно, но это будет разговор не в терминах языка.
Здравствуйте, Трурль, Вы писали:
Т>В окамле и хаскеле нет функций с несколькими аргументами и нет смысла говорить о частичном применении.
Но тем не менее говорят. Хотя этот термин действительно не является необходимым.
Т>Точнее, говорить то можно, но это будет разговор не в терминах языка.
Здравствуйте, Трурль, Вы писали:
Т>Да, говорят. Так же, как сишники говорят об объектах и методах. Т>Просто рассуждать о сложении, как о Int -> Int -> Int очень неудобно.
Здравствуйте, Трурль, Вы писали:
Т>Алгоритм — вряд ли. Но можно придумать эмпирическое правило. Если все сводится чисто к синтаксическим преобразованиям, то это синтаксический сахар (или иногда синтаксический крысиный яд). Если же в дело вмешивается семантика, возникают новые понятия, то это уже абстрация.
ОК. Вот в C# есть using. Он в общем-то является сахаром для ручной реализации паттерна Dispose обеспечивающего детерминированый контроль освобождения ресурса (РАЮ, тык сызыть).
Т>Например, for — чистый сахар, а foreach — нет. И даже for в паскале нельзя считать просто сахаром.
Вот только for можно выразить через foreach, в foreach через for. В том же Немерел и foreach и for реализованы макросами на базе рекурсивных фунций.
Т>Конечно, все это имеет смысл, если мы выделяем некоторое ядро языка. Собственно, термин возник, когда Ландин обозвал let синтаксическим сахаром для лямбды.
Раз нет четкого алгоритма разделения на сахар и фичи, то все это балшит. Им можно пользоваться в выразительных целях, но и только. Четко утверждать, что что-то есть сахар, а что-то другое фича няльзя. Иначе у одного С++ будет сахаром для С. А у другого даже разный синтаксис лямбд бдудет новой фичей.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VD>Вот только for можно выразить через foreach, в foreach через for. VD>Раз нет четкого алгоритма разделения на сахар и фичи, то все это балшит.
Вот стоит чашка с блюдцем: чашка сверху, блюдце снизу. Теперь я поставил блюдце на чашку. Получилось блюдце сверху, чашка снизу. Значит ли, что "сверху" и "снизу" суть балшит?
И есть ли алгоритм для разделения балшита и небалшита? А если нет алгоритма, то не балшит ли балшит?
Здравствуйте, VladD2, Вы писали:
Т>>Например, for — чистый сахар, а foreach — нет. И даже for в паскале нельзя считать просто сахаром.
VD>Вот только for можно выразить через foreach, в foreach через for.
В С# с соблюдением полной эквивалентности (читай с полученим идентичного IL-кода) нельзя.
... << RSDN@Home 1.2.0 alpha rev. 725 on Windows Vista 6.0.6000.0>>
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Lloyd, Вы писали:
L>>А побитовое или как мило будет выглядеть, просто загляденье L>>(_|_)
VD>Это будет просто ошибкой. Пробелы нужно ставить обязательно.
Занятно. А подчеркивание в Nemerle — это оператор? Зачем?
Здравствуйте, VladD2, Вы писали:
VD>Подчеркивание является виндкардом. Что-то вроде .* в регексах или % в SQL-е.
Я о другом. Требование разделения разных операторов определяется особенностями реализации токенайзера для более полного покрытия всех возможных вариантов операторов. И токенайзер в Nemerle получается разделяет понятия "_" и "_a"?
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, VladD2, Вы писали:
VD>>Подчеркивание является виндкардом. Что-то вроде .* в регексах или % в SQL-е. GZ>Я о другом. Требование разделения разных операторов определяется особенностями реализации токенайзера для более полного покрытия всех возможных вариантов операторов. И токенайзер в Nemerle получается разделяет понятия "_" и "_a"?
Это во многих языках так. Wildcard не оператор, скорее ключевое слово, типа public. Нельзя же писать publicvar вместо public var
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Lloyd, Вы писали:
L>>А побитовое или как мило будет выглядеть, просто загляденье L>>(_|_)
VD>Это будет просто ошибкой. Пробелы нужно ставить обязательно.
На самом деле вполне себе работает и парсится однозначно.
_ = (_|_) (1, 2)
Вот такое правда не совсем правильно отрабатывает
(_|_) (1, 2)
Вместо ожидаемого W:unused имеем E:void!=int. Не могу сказать в какой степени это можно поправить, в общем-то это частный бага #812.
Здравствуйте, deniok, Вы писали:
D>Это во многих языках так. Wildcard не оператор, скорее ключевое слово, типа public. Нельзя же писать publicvar вместо public var
Нет, тут другое. Парсер Nemerle построен с целью, что можно строить любые операторы для использования макросами или перегрузки. Парсер склеивает определенный набор символов предназначенных для операторов, как один токен. Ну например "<>+=" — один оператор. Он не разбирается что это может быть несколько операторов. Он вообще не лезет в семантику операторов. Такой функциональности нет. Если несколько операторов идет подряд, то они должны разделяться whitespace'ами. То же самое и для символьных идентификаторов, то что написал ты. Но если операторы и идентификаторы(строки или цифры) перемешаны с операторами, то требования разделения нет. То есть "sum1+sum2" вполне корректно. И значит если "_" не оператор, то выражение "_==_" вполне корректно.
Здравствуйте, Иванков Дмитрий, Вы писали:
ИД>Вместо ожидаемого W:unused имеем E:void!=int. Не могу сказать в какой степени это можно поправить, в общем-то это частный бага #812.
Здравствуйте, GlebZ, Вы писали:
GZ>Я о другом. Требование разделения разных операторов определяется особенностями реализации токенайзера для более полного покрытия всех возможных вариантов операторов.
Я не в полне уверен... Дело в том, что внутри идетнификаторов "_" допустим и является просто символом.
Так что вполне возможно, что я не прав и при парсинге операторов он тоже воспринимается как одтельная лексема.
GZ>И токенайзер в Nemerle получается разделяет понятия "_" и "_a"?
Это да. Причем от оба являются указанием компилятору. "_" говорит ему, что мы опустили имя переменной, а "_a", что мы создали переменную для которой не недо контролировать используется ли она в программе или нет.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.