Здравствуйте, Максим Рогожин, Вы писали:
МР>Привет! МР>Скажите, пожалуйста, лямбда выражения в C++ являются first class citizens?
Да, посколько результат лямбда выражения это объект (функтор, функциональный объект) типа closure type, который может быть передан в функцию, возвращен из функции, присвоен переменной. Например, код
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Да, посколько результат лямбда выражения это объект (функтор, функциональный объект) типа closure type, который может быть передан в функцию, возвращен из функции, присвоены переменной.
Спасибо! Еще вопрос:
— указатель на функцию
— функтор
тоже являются firts class citizens?
Здравствуйте, Максим Рогожин, Вы писали:
МР>Спасибо! Еще вопрос: МР>- указатель на функцию МР>- функтор МР>тоже являются firts class citizens?
Если у тебя есть определение firts class citizens, как объекта, который может быть передан в качестве аргумента в функцию, возвращен из функции, присвоен переменной, то ты без труда ответишь на свой вопрос
Здравствуйте, Анатолий Широков, Вы писали:
МР>>Скажите, пожалуйста, лямбда выражения в C++ являются first class citizens?
АШ>Да, посколько результат лямбда выражения это объект (функтор, функциональный объект) типа closure type, который может быть передан в функцию, возвращен из функции, присвоен переменной. Например, код
Если да то как массив например их 3 таких лямбд задать?
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, Анатолий Широков, Вы писали:
МР>>>Скажите, пожалуйста, лямбда выражения в C++ являются first class citizens?
АШ>>Да, посколько результат лямбда выражения это объект (функтор, функциональный объект) типа closure type, который может быть передан в функцию, возвращен из функции, присвоен переменной. Например, код
_>Если да то как массив например их 3 таких лямбд задать?
Никак, поскольку массива лямбд не существует в виду того, что объект каждого лямбда выражения является уникальным типом.
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Если у тебя есть определение firts class citizens, как объекта, который может быть передан в качестве аргумента в функцию, возвращен из функции, присвоен переменной, то ты без труда ответишь на свой вопрос
На википедии еще, например, такое требование предъявляется:
— может быть создан во время выполнения программы
Что здесь имеется ввиду? Создание new int(10); ? А лямбда функции мы можем создавать во время выполнения программы? Лямбда функции вроде бы на этапе компиляции уже созданы все будут.
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, kov_serg, Вы писали:
_>>Если да то как массив например их 3 таких лямбд задать?
AG>А в чём проблема?
Все же здесь есть некоторое лукавство Массив лямбд с одинаковой сигнатурой функционального оператора невозможен по определению:
assert(typeid([]{}) != typeid([]{}));
поскольку я не могу вывести общий тип для таких выражений.
Здравствуйте, Анатолий Широков, Вы писали:
AG>>А в чём проблема?
АШ>Все же здесь есть некоторое лукавство
Всё легально, лямбду можно копировать в переменную того же типа.
И даже в теории конструкция может быть полезна для лямбд с захватом по значению: у элементов может быть разное состояние.
АШ>Массив лямбд с одинаковой сигнатурой функционального оператора невозможен
Ну это да, разные лямбды — разные типы.
Но почему массив из одной и той же лябмды не считается?
Те же массивы объектов работают только если это один и тот же класс, т.е. нельзя:
class X{};
class Y{};
decltype(X) a[] = { X{}, Y{} };
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, kov_serg, Вы писали:
_>>Если да то как массив например их 3 таких лямбд задать?
AG>А в чём проблема? AG>
Проблема в том что для first class citizen такой проблемы не должно быть
auto x=[]{ std::cout<<"x\n"; };
auto y=[]{ std::cout<<"y\n"; };
auto z=[]{ std::cout<<"z\n"; };
typedef decltype(x) t;
void foo(t); foo(x); foo(y); foo(z);
t a[]={x,y,z};
В C++ стараются сделать костылями. Именно это печалит. Что указатели на члены класса что лямбды. А перегружаемые функции с лямбдами. А если вируальную функцию захочеться? В результате таких нововедений растёт только сложность и энтропия и вместо упрощения получаем новые проблемы.
Так что это не "first class citizen" это "crutch class outlander".
Я уже ответил, массив различных лямбда выражений не существует в С++, они ничем не связаны. Хочешь массив, объявляй массив указателей на функцию и приводи к ним лямбда выражения без захвата.
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Я уже ответил, массив различных лямбда выражений не существует в С++, они ничем не связаны. Хочешь массив, объявляй массив указателей на функцию и приводи к ним лямбда выражения без захвата.
Причем тут чего я хочу. Я просто сказал, что это костыли, а не типы данных. Тем более не "first class citizen".
То что в C++ это сделано через жопу, я не виноват. А вы просто констатируете факт что для этих костылей нужны еще костыли в виде указателей на функцию (тут одельная песня).
Для "first class citizen" int и double я могу написать такое
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, Анатолий Широков, Вы писали:
АШ>>Я уже ответил, массив различных лямбда выражений не существует в С++, они ничем не связаны. Хочешь массив, объявляй массив указателей на функцию и приводи к ним лямбда выражения без захвата. _>Причем тут чего я хочу. Я просто сказал, что это костыли, а не типы данных. Тем более не "first class citizen".
Все норм, лямбда нормально подходит на звание first class citizen, просто с массивами напряженка в виду отсутствия базового типа, к которому может быть приведено лямбда-выражение. Но даже в этом случае у тебя есть возможность сохранить лямбду в std::function.
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Если у тебя есть определение firts class citizens, как объекта, который может быть передан в качестве аргумента в функцию, возвращен из функции, присвоен переменной, то ты без труда ответишь на свой вопрос
на самом деле функции в сях таковыми не являются, хотя и подходят под твое определение. как минимум я сторонник такого мнения (читаем вики)
Some authors require it be possible to create new functions at runtime to call them 'first-class'. As a result, functions in C are not first-class objects; instead, they are sometimes called second-class objects, because they can still be manipulated in most of the above fashions (via function pointers).
функции в сях не являются первоклассными, хотя являются первоклассными в питоне, хаскеле и жава-скрипте
std::function является первоклассной сущностью
U>Some authors require it be possible to create new functions at runtime to call them 'first-class'. As a result, functions in C are not first-class objects; instead, they are sometimes called second-class objects, because they can still be manipulated in most of the above fashions (via function pointers).
U>функции в сях не являются первоклассными, хотя являются первоклассными в питоне, хаскеле и жава-скрипте
Можете привести пример, того что значит создать функцию at runtime? И как это могло бы выглядеть в C++?
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, Анатолий Широков, Вы писали:
МР>>>Скажите, пожалуйста, лямбда выражения в C++ являются first class citizens?
АШ>>Да, посколько результат лямбда выражения это объект (функтор, функциональный объект) типа closure type, который может быть передан в функцию, возвращен из функции, присвоен переменной. Например, код
_>Если да то как массив например их 3 таких лямбд задать?
Никак, это уникальные типы.
Я правильно понимаю, что по твоей логике, уникальные типы не являются first class citizens?
Здравствуйте, jazzer, Вы писали:
J>Никак, это уникальные типы. J>Я правильно понимаю, что по твоей логике, уникальные типы не являются first class citizens?
Да. Я хочу сначала объявить переменную а потом присвоить. Или присвоить в зависимости от флага одну или другую функцию.
Вернуть из функции в из разных return-ов и т.п.
Здравствуйте, kov_serg, Вы писали:
_>Да. Я хочу сначала объявить переменную а потом присвоить. Или присвоить в зависимости от флага одну или другую функцию. _>Вернуть из функции в из разных return-ов и т.п.
Только если значение флага вычисляется в компайл-тайм, т.е. объявлен флаг как constexpr.
Здравствуйте, kov_serg, Вы писали:
J>>Я правильно понимаю, что по твоей логике, уникальные типы не являются first class citizens? _>Да. Я хочу сначала объявить переменную а потом присвоить.
твои хотелки никак не связаны с понятием first class citizen, не мешай всё в кучу
лямбды в плюсах сделали очень легковесными, это жирный плюс
твои хотелки реализуются с помощью std::function, который имеет бОльший оверхед, нежели лямбды и достаточно просто создаются из лямбд
по-моему, по сравнению с теми же bind + placeholders, лямбды в язык вписались довольно гармонично (хотя, синтаксис чудноват, имхо) и любителям перформанса не очень больно
Здравствуйте, uzhas, Вы писали:
U>твои хотелки никак не связаны с понятием first class citizen, не мешай всё в кучу U>лямбды в плюсах сделали очень легковесными, это жирный плюс U>твои хотелки реализуются с помощью std::function, который имеет бОльший оверхед, нежели лямбды и достаточно просто создаются из лямбд
Это first class citizen? Это как для передачи char использовать double.
U>по-моему, по сравнению с теми же bind + placeholders, лямбды в язык вписались довольно гармонично (хотя, синтаксис чудноват, имхо) и любителям перформанса не очень больно
На вкус и цвет карандаши разные.
Здравствуйте, kov_serg, Вы писали:
_>Это first class citizen?
да: https://wandbox.org/permlink/oEFfJUfH0z0CuoBh
твой тернарный оператор не имеет никакого отношения к first-class. иди вики почитай уже или внятно объясни, где ты видишь несостыковки с понятием first-class
"мне неудобно" — это не обоснование, т.к. first-class не об удобстве, а о возможностях. плюсовые лямбды предоставляют те возможности, которые прописаны для first-class объектов (пусть даже и неудобно кому-то). если быть точнее, то лямбды соответствуют тем критериям\условиям, которые определены для всех first-class объектов
это всё равно, что заявлять, что обработка double не соответствует IEEE754. т.к. при печати 0.1 выдаётся куча девяток после запятой. ну да, кому-то неудобно, но это не значит, что double не соответствует стандарту IEEE
короче, с логикой явные проблемы
Здравствуйте, uzhas, Вы писали:
U>да: https://wandbox.org/permlink/oEFfJUfH0z0CuoBh U>твой тернарный оператор не имеет никакого отношения к first-class. иди вики почитай уже или внятно объясни, где ты видишь несостыковки с понятием first-class
Michael L. Scott, Programming Language Pragmatics, 3-rd ed., ELSEVIER 2011
ISBN 13: 978-0-12-374514-9
Page:154
3.6.2 First-Class Values and Unlimited Extent
In general, a value in a programming language is said to have first-class status if it can be passed as a parameter, returned from a subroutine, or assigned into a variable.
Simple types such as integers and characters are first-class values in most programming languages.
By contrast, a “second-class” value can be passed as a parameter, but not returned from a subroutine or assigned into a variable,
and a “third-class” value cannot even be passed as a parameter.
Делаем виртуальнкю функцию, которая принимает лямду как параметр и в зависимости от того совпала она с предыдущим значением которое передавали в эту функцию
возвращает лямду 1 или лямду 2.
struct A {
lambda prev;
virtual lambda fn( lambda a ) {
if (a==prev) return []{ one };
prev=a;
return []{ two };
}
};
Для first class int это выглядит так:
struct A {
int prev;
virtual int fn(int a) {
if (a==prev) return 1;
prev=a;
return 2;
}
};
U>"мне неудобно" — это не обоснование, т.к. first-class не об удобстве, а о возможностях. плюсовые лямбды предоставляют те возможности, которые прописаны для first-class объектов (пусть даже и неудобно кому-то). если быть точнее, то лямбды соответствуют тем критериям\условиям, которые определены для всех first-class объектов
U>это всё равно, что заявлять, что обработка double не соответствует IEEE754. т.к. при печати 0.1 выдаётся куча девяток после запятой. ну да, кому-то неудобно, но это не значит, что double не соответствует стандарту IEEE U>короче, с логикой явные проблемы
Я имел ввиду что это выглядит так как если бы для char приходилось писать
char r = flag ? (double) char(65) : (double) char(48);
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, kov_serg, Вы писали:
_>>first-class status if it can be passed as a parameter, returned from a subroutine, or assigned into a variable.
U>проверяем все три пункта: U>https://wandbox.org/permlink/sQ8zFvdmI61NIx6M U>вот и виртуальная функция и без шаблонов: https://wandbox.org/permlink/epZyEGUG9MGcgu7y
Где присвоение переменной? Где без кастыльная возможность вернуть лямды в разных ветках switch-а ?
Где возможноть передавать назные лямды в одну виртуальную функцию?
Невижу.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, uzhas, Вы писали:
U>>да: https://wandbox.org/permlink/oEFfJUfH0z0CuoBh U>>твой тернарный оператор не имеет никакого отношения к first-class. иди вики почитай уже или внятно объясни, где ты видишь несостыковки с понятием first-class _>
_>Michael L. Scott, Programming Language Pragmatics, 3-rd ed., ELSEVIER 2011
_>ISBN 13: 978-0-12-374514-9
_>Page:154
_>3.6.2 First-Class Values and Unlimited Extent
_>In general, a value in a programming language is said to have
_>first-class status if it can be passed as a parameter, returned from a subroutine, or assigned into a variable.
_>Simple types such as integers and characters are first-class values in most programming languages.
_>By contrast, a
_>“second-class” value can be passed as a parameter, but not returned from a subroutine or assigned into a variable,
_>and a
_>“third-class” value cannot even be passed as a parameter.
Попробуем по порядку.
first-class status if it can be passed as a parameter,
#include <iostream>
#include <memory>
using namespace std;
void f(auto) {}
int main()
{
f([]{});
}
returned from a subroutine, or assigned into a variable
#include <iostream>
#include <memory>
using namespace std;
auto f() { return []{return 1;}; } // returned from a subroutineint main()
{
auto l = f(); // assigned into a variablereturn l();
}
Приведённые требования выполняются.
Значит по мнению Michael L. Scott лямбды first-class values
_>А виртуальную функцию как? А экспортировать эту функцию как, перегдужать как? То что вы привели шаблон, а не функция.
Тогда стоит для начала уточнить требования.
Я не знаю, что автор утверждения говорит насчёт шаблонов, виртуальных функций, экспорта (что такое экспорт ?) и перегрузки (о чём речь?).
Это всё не приводилось в качестве обязательных требований.
Если без шаблоном то очевидно никак нельзя заранее указать тип лямбды потому как он выводится из самой лямбды.
Однако мы можем указать тип после и передать лямбду в качестве параметра тем самым имея нешаблонную функцию и отвечая требованию 1.
int main()
{
auto x = []{};
auto f = [](decltype(x)) {};
f(x);
}
Собственно виртуальность не проблема:
class A
{public:
static constexpr auto x = []{};
virtual void f(decltype(x)) {} // Объявляем
};
class B:public A
{
void callf()
{
f(x); // Вызываем
}
virtual void f(decltype(A::x)) override {}
};
_NN>>
returned from a subroutine, or assigned into a variable
_NN>>
_NN>>#include <iostream>
_NN>>#include <memory>
_NN>>using namespace std;
_NN>>auto f() { return []{return 1;}; } // returned from a subroutine
_>[c]
_>auto f(int f) { if (f) return [=]{return f;}; return [=]{return f-1;}; }
_>
_>И где?
Где что ?
Во первых это не относится к требования first-class из цитаты.
Во вторых оператор ?: требует одинаковые типы, а типы не одинаковые.
Этот код аналогичен
struct A{};
struct B{};
A x(int f)
{
if (f) return A();
return B();
}
_NN>>int main() _NN>>{ _NN>> auto l = f(); // assigned into a variable _NN>> return l(); _NN>>} _NN>>[/c] _>Assigned into variable _>
_> l=f(); l=f(); // не работает
_>
_NN>>Приведённые требования выполняются. _>и где они выполняются?
Тут у нас похоже разные трактования 'assigned into a variable'.
Я считаю, что если можно создать объект и передать ему значение, то требование выполняется.
С вашей стороны есть дополнительное требование, которое мне неясно имел ввиду автор или нет, а именно создание пустого значения переменной этого типа и последующее присовение.
Для лямбды копирование запрещено , но есть перемещение
Получается по этой логике тип с приватным конструктором либо с запретом на конструктор копирования или присваивания не является first-class, так ?
Здравствуйте, _NN_, Вы писали:
_NN>Если без шаблоном то очевидно никак нельзя заранее указать тип лямбды потому как он выводится из самой лямбды. _NN>Однако мы можем указать тип после и передать лямбду в качестве параметра тем самым имея нешаблонную функцию и отвечая требованию 1.
Вы смотрите со стороны C++. Если даже если это реализовано неудачно вы будете настаивать на обратном.
Вот представте что тип для каждого целого числа был уникален. Очень удобно да?
_NN>Во вторых оператор ?: требует одинаковые типы, а типы не одинаковые.
Дык в этом и есть претензия что работать напрямую с ними нельзя. Только через переходники и другие типы.
_NN>Тут у нас похоже разные трактования 'assigned into a variable'. _NN>Я считаю, что если можно создать объект и передать ему значение, то требование выполняется.
Посмотрите как сделано в других языках и поймёте что в C++ не лучшая реализация.
_NN>Для лямбды копирование запрещено, но есть перемещение _NN>Получается по этой логике тип с приватным конструктором либо с запретом на конструктор копирования или присваивания не является first-class, так ?
Это уже особенности развития C++(n+1).
Я вот одного не пойму почему каждый считает своим долго защищать глупости которые постоянно добавляют в стандарт.
При этом с пеной у рта доказывать что реализовать можно только так и никак иначе и ещё ссылку на стандарт кинуть.
Как-будто это доказательство, что это истина в последней инстанции. Это напоминает про милион мух которые не могут ошибаться.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, jazzer, Вы писали:
J>>Никак, это уникальные типы. J>>Я правильно понимаю, что по твоей логике, уникальные типы не являются first class citizens? _>Да. Я хочу сначала объявить переменную а потом присвоить. Или присвоить в зависимости от флага одну или другую функцию. _>Вернуть из функции в из разных return-ов и т.п.
Жжешь
По твоей логике, объекты классов в С++ — не first class citizens, потому что у них может не оказаться оператора присваивания
Здравствуйте, jazzer, Вы писали:
J>По твоей логике, объекты классов в С++ — не first class citizens, потому что у них может не оказаться оператора присваивания
Это всего лишь классификация и она ни на что не влияет.
Если не будет оператора присвоения то соответственно это значение будет не first class.
У вас совсем определение первоклассной сущности это:
Возможность конструировать тип с конструктором без параметров.
Возможность копировать объект через присваивание.
Возможность копировать объект через конструктор копирования.
Очевидно лямбда, являющаяся типов без возможности создания пустого объекта и копирования. не подходит под это определение.
Если это и так было понятно зачем было поднимать тему ?
Могу отметить, что большинство классов не имеют возможности копирования.
Будем всех считать второклассными сущностями ?
Здравствуйте, _NN_, Вы писали:
_NN>Могу отметить, что большинство классов не имеют возможности копирования. _NN>Будем всех считать второклассными сущностями ?
Да если они попадают во второй класс.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, jazzer, Вы писали:
J>>По твоей логике, объекты классов в С++ — не first class citizens, потому что у них может не оказаться оператора присваивания _>Это всего лишь классификация и она ни на что не влияет. _>Если не будет оператора присвоения то соответственно это значение будет не first class.
Если она ни на что не влияет, то какой в ней смысл тогда?
Вот я объявил объект типа int — и это объект первого класса.
А если я объявлю const int — в него нельзя присвоить, вообще с ним ничего нельзя сделать, кроме как инициализировать и прочитать значение — и что, это объект второго класса?
Что там такая классификация дает?
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, jazzer, Вы писали:
J>>Что там такая классификация дает? _>Она просто удобна при обучении студентов. Вам она скорее всего не понадобиться.
Она удобна в плане сравнения возможностей языков. Но при таком сравнении никто не привязывается к деталям конкретных реализаций. Просто — есть ли возможность. Если возможность предоставлена в виде std::function — этого с головой достаточно. Потому что это всего лишь означает, что в других языках std::function сидит везде и неявно, а она небесплатна, а в С++ ты не должен платить за то, что не используешь.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, _NN_, Вы писали:
_NN>>Если без шаблоном то очевидно никак нельзя заранее указать тип лямбды потому как он выводится из самой лямбды. _NN>>Однако мы можем указать тип после и передать лямбду в качестве параметра тем самым имея нешаблонную функцию и отвечая требованию 1. _>Вы смотрите со стороны C++. Если даже если это реализовано неудачно вы будете настаивать на обратном. _>Вот представте что тип для каждого целого числа был уникален. Очень удобно да?
числа друг от друга никак не отличаются. А объекты-лямбды даже с одной сигнатурой имеют разный размер в зависимости от того, что было захвачено.
А объекты с неизвестным в рантайме размером (и, соответственно, типом) на стек (и в массив, ага) не положишь — так что остается только динамическая память, общий базовый класс и виртуальные вызовы.
Внезапно, именно это и обеспечивает std::function.
Так что ты определись, тебе шашечки или ехать.
_NN>>Тут у нас похоже разные трактования 'assigned into a variable'. _NN>>Я считаю, что если можно создать объект и передать ему значение, то требование выполняется. _>Посмотрите как сделано в других языках и поймёте что в C++ не лучшая реализация.
В других языках, скорее всего, лямбд в смысле C++ (т.е. без накладных расходов) вообще нет, только аналог std::function, со всеми сопутствующими расходами.
Причем в плюсах и писать-то надо не намного больше, чем, скажем, в JS:
Здравствуйте, kov_serg, Вы писали:
_NN>> auto l = f(); // assigned into a variable _>Не объявление константы, а присвоение переменной. _>
_> l=f(); l=f(); // не работает
_>
_NN>>Приведённые требования выполняются. _>и где они выполняются?
В функциональных языках типа семейства ML или хаскелла, например, вообще нет переменных.
Там все "переменные" — это рантаймовые константы.
А теперь давайте поговорим про непервоклассность функций в мл.
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, _NN_, Вы писали:
_NN>>Если без шаблоном то очевидно никак нельзя заранее указать тип лямбды потому как он выводится из самой лямбды. _NN>>Однако мы можем указать тип после и передать лямбду в качестве параметра тем самым имея нешаблонную функцию и отвечая требованию 1. _>Вы смотрите со стороны C++. Если даже если это реализовано неудачно вы будете настаивать на обратном. _>Вот представте что тип для каждого целого числа был уникален. Очень удобно да?
Добро пожаловать в TypeScript:
const a = 1;
const b = 2;
if (a == b) { // Operator == cannot be applied to type '1' and '2'
}
Здравствуйте, Максим Рогожин, Вы писали:
МР>Скажите, пожалуйста, лямбда выражения в C++ являются first class citizens?
Как-то так должны бы были бы выглядеть λ что бы быть first class