LINUX.ORG.RU

Скрестить ужа с ежём: first-class функции vs методы, как частный вид функций

 , , ,


1

1

Навеяно чьими-то сообщениями в темах про ООП, что прочел давно, но не было времени сформулировать проблему...

Итак предположим, что в нашем языке функции - это объекты, а объекты могут иметь методы. У функций есть специальный метод apply(call, operator(), etc.), который вызывается при вызове функции. В этом случае получается, что методы не могут являться first-class объектами и разновидностью функций, т.к. тогда у них должен быть метод apply, который в свою очередь должен иметь метод apply, который и т.д. и т.д.

Решения у нас могут быть примерно такие:

- или мы делаем как в крестах и получаем не first-class функции/методы, но имеем возможность сделать «объект-функцию»(в том числе через лямбды), если потребуется;

- или мы делаем как в scala и получаем довольно стройную систему, но отказываемся от простой очевидной концепции метода как частного вида функции и, как следствие, от first-class методов;

- или мы делаем «функции» особым видом объектов, который нельзя сделать в обход механизма создания функций(определив для объектов какого-то типа apply или operator());

Я правильно понимаю? Или можно таки разорвать цепочку красиво?


Ответ на: комментарий от monk

Также и вызов. Можно писать f(x, y), можно f.apply(x, y), можно f.apply.apply(x, y), ..., f.apply.apply.apply.apply.apply.apply(x, y). Они все эквивалентны.

Непонятно, почему они эквиваленты, если объекты apply разные.

anonymous ()
Ответ на: комментарий от idiottoop

У функций есть специальный метод apply(call, operator(), etc.), который вызывается при вызове функции. В этом случае получается, что методы не могут являться first-class объектами и разновидностью функций, т.к. тогда у них должен быть метод apply, который в свою очередь должен иметь метод apply, который и т.д. и т.д.

Я чет не понял, почему утебя так получается, но в JS так оно и есть, как ты описал: у ф-ций есть специальные методы call и apply, и при этом методы являются 100% first.

Ну вот сами эти методы call/apply так же являются объектами с методами call/apply, которые так же являются методами call/apply и т.д. Именно это смущает ТС, как я понял его (пьяный?) бред.

anonymous ()
Ответ на: комментарий от anonymous

Там вроде методы не являются полноценными объектами, полноценными объектами является т.н. «Method Value». А остальное - синтаксический сахар.

anonymous ()
Ответ на: комментарий от user_id_68054

автор темы завёл разговор о том что если есть некий __call__ у функции, то должен быть и этот __call__ у самой функции __call__ .

и он начал опасаться что этих __call__ будет бесконечно!

но в равенство type(type(f).__call__).__call__ == type(type(type(f).__call__).__call__).__call__ показывает что в определённом уровне метакласса — просто цепочка объектов ссылается сама на себя (замкнутая связь).

Тут проблема в том, что число аргументов метода __call__ на разных уровнях должно быть разным(+1 на каждом уровне), разве не так?

anonymous ()
Ответ на: комментарий от anonymous

Метод объекта также является объектом, с как минимум одним методом, который является объектом с как минимум одним методом, который... Эпик фэйл! 😊 Где же разгадка?

bogus_result ()
Ответ на: комментарий от bogus_result

Я же писал выше, разгадка проста

Function.call===Function.call.call // true

это одна и та же функция. Просто в условиях современного статик-блядства, люди не понимают вообще, что так может быть. метод — это просто ссылка на функцию. В питоне, кстати, насколько я понял, это не так. Там костыльная какая то реализация.

idiottoop ()
Ответ на: комментарий от bogus_result

Даже не так... В какой же книге простым и доступным языком описывается разгадка?

bogus_result ()
Ответ на: комментарий от bogus_result

Вот над этим помедитируй


Function.prototype.call1=function(x, optional){return this.call(x, optional)}
Function.prototype.call2=Function.call

f=function(x){console.log(this.x+this.x)}

f.call1({x: 5})
f.call2({x: 4})

console.log(
   f.call1===Function.call1,
   f.call1===f.call1.call1,
   f.call2===f.call1,
   f.call2===f.call
)

//  10
//  8
//  true true false true
А книги — бери любую по прототипному программированию, и втыкай. Также подумай о разнице между ранним и поздним связыванием.

idiottoop ()
Ответ на: комментарий от idiottoop

Детсад какой-то.

In [14]: arr = [lambda: 1, lambda: 2, "foo", lambda: 3]

In [15]: arr
Out[15]: 
[<function __main__.<lambda>>,
 <function __main__.<lambda>>,
 'foo',
 <function __main__.<lambda>>]

In [16]: print(arr[1]())
2

In [17]: f = lambda: "baz"

In [18]: f.foo = "bar"

In [19]: print([f,f,f][1].foo)
bar

In [20]: print([f,f,f][1]())
baz

loz ★★★★★ ()
Ответ на: комментарий от loz

не распинайся, уже выяснили, что ф-ци в питоне ферст, я понял, да.

idiottoop ()
Ответ на: комментарий от idiottoop

метод — это просто ссылка на функцию

И каким образом это разруливает проблему? Эта функция, на которую мы имеем ссылку, представляет собой объект с методом, который является ссылкой на функцию и т.д. Если ты замкнешь цепочку ссылкой на объект-функцию какого-то из уровней является костылем для метода apply/call.

anonymous ()
Ответ на: комментарий от loz

Кстати, раз уж зашел разговор, интересно, а вот так питон может?


f=function(arg){var a=1; return eval(arg)}
console.log(f("a"))
// 1
т.е. захватить евалом внутрений контекст ф-ции?

idiottoop ()
Ответ на: комментарий от anonymous

И каким образом это разруливает проблему? Эта функция, на которую мы имеем ссылку, представляет собой объект с методом, который является ссылкой на функцию и т.д. Если ты замкнешь цепочку ссылкой на объект-функцию какого-то из уровней является костылем для метода apply/call.

ЯННП. И что разруливать какую проблему? Это проблема только для статики, в нормальном языке нет там никаких проблем, см. выше

idiottoop ()
Ответ на: комментарий от anonymous

Функции, никто не мешает ссылаться на себя саму, если чо


f=function(){console.log(1)}
f.c=f
f.c()
//  1

idiottoop ()
Ответ на: комментарий от idiottoop

Проблема никак не связана со статикой/динамикой. Она концептуальная. И в ваших примерах я не вижу решения, может TC увидит, хз.

anonymous ()
Ответ на: комментарий от idiottoop

Правильно. А что будет, если мы каким-то образом в теле функции вызовем c? И почему это не происходит всегда, ведь мы вызываем метод apply, который вы предлагаете зациклить на самого себя(или на другой уровень)?

anonymous ()
Ответ на: комментарий от idiottoop

В общем, резюме такое - чтоб рассуждать об объектах, методах как объектах, объектно-ориентированном программировании, моделях ООП и тд. нужно иногда читать умные книги. Тот вопрос, который в этом топике вызвал столько споров, прекрасно описан в книге CTMCP.

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

Попробуйте вначале описать модель вычислений, в которой G.f() и f.call() вычисляются однообразно, и при условии f.call==f.call.call вычисление функции f когда-либо прекратится.

bogus_result ()
Ответ на: комментарий от anonymous

Она концептуальная

в чем проблема заключается, на пальцах можешь объяснить? Странные у тебя какие-то «проблемы», я тебе рассказал, как это работает, а ты о какой-то проблеме в вакууме. ТО что вода из под крана течет это тоже концептуальная проблема?

А статика тут притом, что статический метод является, обычно, отдельной функцией, привязанной к своему скопу. Поэтому, этот метод не может работать одинаково для всех объектов, потому что он никогда не увидит их неймспейсы.

idiottoop ()
Ответ на: комментарий от anonymous

А что будет, если мы каким-то образом в теле функции вызовем c?

А что бывает, когда ф-ция вызывает сама себя? рекурсия, очевидно.

И почему это не происходит всегда, ведь мы вызываем метод apply, который вы предлагаете зациклить на самого себя(или на другой уровень)?

А почему это должно происходить, я не понял?

idiottoop ()
Ответ на: комментарий от bogus_result

Попробуйте вначале описать модель вычислений, в которой G.f() и f.call() вычисляются однообразно, и при условии f.call==f.call.call вычисление функции f когда-либо прекратится.

По моему, вы застопорились на детской проблеме — Вы не можете отличить вызов функции от самой функции.

idiottoop ()
Ответ на: комментарий от idiottoop

А почему это должно происходить, я не понял?

Если в качестве решения, вы предлагаете, чтоб на каком-то уровне apply ссылался на самого себя или apply «выше», то мы получим именно эту ситуацию.

anonymous ()
Ответ на: комментарий от anonymous

Если в качестве решения, вы предлагаете, чтоб на каком-то уровне apply ссылался на самого себя или apply «выше», то мы получим именно эту ситуацию.

все apply ссылаются на одну и ту же функцию. Нет там никаких уровней, и никаких разных функций. Есть множество ссылок на одно и то же.

idiottoop ()
Ответ на: комментарий от bogus_result

Тот вопрос, который в этом топике вызвал столько споров, прекрасно описан в книге CTMCP.

Ну так кратенько поделитесь идеей.

anonymous ()
Ответ на: комментарий от idiottoop

все apply ссылаются на одну и ту же функцию. Нет там никаких уровней, и никаких разных функций. Есть множество ссылок на одно и то же.

А эта функция имеет метод apply? На что ссылается он?

anonymous ()
Ответ на: комментарий от anonymous

А эта функция имеет метод apply? На что ссылается он?

этот метод — это всего лишь ссылка на объект в котором эта ссылка сама же и находится.

idiottoop ()
Ответ на: комментарий от idiottoop

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

Когда она будет представлена, все мы увидим, что проблема детская.

bogus_result ()
Ответ на: комментарий от idiottoop

этот метод — это всего лишь ссылка на объект в котором эта ссылка сама же и находится.

тут я немного упростил, конечно, реально, в JS эта ссылка получается динамически из прототипа, обычно, наследуется из Function.ptototype, но это не особо важно, в данном контексте. Строго говоря, то что я описал, справедливо на 100% только для Function.ptototype.call — именно тут содержиться непосредственно поле ссылки на нативный call

idiottoop ()
Ответ на: комментарий от anonymous

Да нет никакой большой и сложной идеи. Модель вычислений нужно описать. Из неё всё следует. В книге просто модель вычислений описана - аккуратно, но авторы выбрали такой подход, при котором в языке есть ядро, и модель вычислений описана для ядра, а ООП выражается через ядро. Сами понимаете, пересказ при таком подходе будет долгим.

bogus_result ()
Ответ на: комментарий от idiottoop

Так нативный call объектом уже не является. Фактически вы предлагаете первый вариант ТС, только со спрятанным под капотом нативными функциями, т.е. с лишением возможности создания таких функций со стороны пользователя.

Но дело не в реализации. А в самой концепции методов как объектов и модели вызова.

anonymous ()
Ответ на: комментарий от idiottoop

И вот мы «вызываем» функцию, т.е. её метод call, который сам является объектом, мы, соответственно, вызываем его, т.е. его метод call, который сам является объектом...

anonymous ()
Ответ на: комментарий от anonymous

Смотри, короче, попробую подробней.

Есть ссылка на нейтив код в объекте, доступном по адресу Function.prototype.call. когда я вызываю Function.prototype.call.call — тут последний call — это не непосредственная ссылка на нейтив. Это ф-ция, которая наследует от Function.prototype и вызывается тот же самый объект, доступный по адресу Function.prototype.call но я могу сделать и так, например

call=Function.prototype.call

у нас теперь 2 ссылки. Объект [native call] доступен теперь по двум разным адресам

1)Function.prototype.call

2)call

PS меня забанили, я idiottoop, если чо. Тут один модератор есть, полный ноль в программировании, берется судить о темах в development, судит он видать, по отзывам в самой же теме. Синдром дауна и вахтера в одном флаконе, LOL

anonymous ()
Ответ на: комментарий от anonymous

Вот вот. Все знают как из замыканий/функций и правил их вычисления сделать концепцию объектов с наследованием, блекджеком и шлюхами. Но наоборот - когда элементарные единицы это объекты, интересно посмотреть на модель вычислений.

bogus_result ()
Ответ на: комментарий от anonymous

native call имеет метод call? Нет? Это первый вариант TC. В крестах та же херня, только пользователь языка может задавать как нативные функции, так и функции-объекты.

anonymous ()
Ответ на: комментарий от anonymous

Да ты, похоже не догоняешь, что такое объект. Объект — это набор ссылок на что-то. И мы вобже абстрагированны от нейтива, любая строка или число, это тоже нейтив, но на нашем уровне абстракции — это объект. На самом деле есть только транзисторы, епт. надо уметь рассуждать абстрактно. Если у тебя есть в ЯП ссылка, или набор их, которая указывает на что-то-там — это объект, и не важно, на что он указывает. Ты на своем уровне находишься. function(){[native]} ничем не отличается от function(){foo}, оба они имеют свое внутреннее представление, от которого ты абстрагирован.

anonymous ()
Ответ на: комментарий от bogus_result

Моё недоумение можно объяснить так. Когда у нас есть замыкание, в теле которого несколько имён не связаны, мы можем вычислить его тело в окружении, которое связывает указанные имена.

Но когда у нас есть только объекты, которые могут посылать друг другу сообщения.... Становится непонятно, как что вычислять.

bogus_result ()
Ответ на: комментарий от anonymous

Да. Но в данном случае именно за счёт native ты разрываешь цепочку и решаешь проблему ТС. Но он сам описал этот вариант, первым же пунктом.

anonymous ()
Ответ на: комментарий от bogus_result

Замыкание можно точно также трактовать в контексте семантики сообщений. замыкание — это функция+окружение===объект. Просто это ограниченная модель, но она тоже частный случай актора.

anonymous ()
Ответ на: комментарий от anonymous

Ничего не разрывается засчет нейтива. Я получаю нейтив как любой другой объект. нет никакой разницы. Можно нейтив зациклить, можно не нейтив, это вообще параллельно.

anonymous ()
Ответ на: комментарий от anonymous

Как это не разрываешь, когда разрываешь? Ведь native call не является объектом с методом call, в отличие от любых других методов/функций.

anonymous ()

Думается мне это навеяно моими сообщениями. Что ж.

Фундаментально функция это никак не объект и точка. Объект это функции(методы) + состояние. Можешь представить себе граф, какие то состояния и переходы между ними. Вот переходы это у нас функции. А весь граф с его состояния и переходами будет объектом. Почти нормально все это сделали в Go.

anonymous ()
Ответ на: комментарий от anonymous

Да какая разница чем он является? это черный ящик. ты говоришь исполнителю, дая мне черный ящик с таким то поведением. Когда ты получил его, ты говоришь ему, слелай то, что я ожидаю от тебя. И все. Точно также, как и к любой другой ф-ции. А так, да, нет ничего, ни текста, ни кода ни цифр, ни самого нейтива. Это ты должен сам абстрагировать все эти сущности. Твой взгляд решает.

anonymous ()
Ответ на: комментарий от anonymous

Ведь native call не является объектом с методом call

именно, что нейтив call на нашем уровне абстракции, и в соответствии с семантикой языка является точно таким же объектом, как и все остальное. Есть нативный ForEach, я могу написать свой forEach. Какая разница между ними, с точки зрения семантики? Никакой.

anonymous ()
Ответ на: комментарий от anonymous

Ну тогда, если по аналогии с акторами, вот и опишите на примере, как вычисляется какой-нибудь простой случай вычисления G.f() и как это завязано на f.call(). Пусть объект может в ответ на полученное сообщение: отправить конечное число сообщений, создать конечное число объектов, и выбрать как он будет реагировать... (нувыпонели, акторы). И тогда все будут довольны.

bogus_result ()
Ответ на: комментарий от idiottoop

Да, вполне:

In [1]: def f(x):
   ...:     y = 1
   ...:     return eval(x)
   ...: 

In [2]: f("y")
Out[2]: 1

Правда лямбдой не написать, что-что, а лямбды в питоне говно.

loz ★★★★★ ()
Последнее исправление: loz (всего исправлений: 1)
Ответ на: комментарий от anonymous

Ещё раз. Смысл посыла ТС в том, что если метод - объект, то значит у него так же есть методы, одним из которых является метод call, который и вызывается при «вызове» объекта, так вот этот call так же является в нашей модели методом, а значит и объектом, у которого так же есть метод call и т.д.

Ты разрываешь цепочку посредством deus ex machina - некоего native call, который как бы и объект, но вызвать его можно напрямую, без какого-либо метода call.

И еще раз говорю - этот вариант есть в исходном сообщении.

anonymous ()
Ответ на: комментарий от bogus_result

Все это делается, просто надо понимать что такое сообщения, что такое конечное число объектов и тд. А этого, то как раз, обычно не понимают. Это мутная тема, не для форума. Любая модель вычислений, в том числе машина тьюринга — это частный случай модели акторов.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.