LINUX.ORG.RU

Вопрос про обобщенные функции

 , , ,


1

3

Пишут, что это необычайно мощная весчь. Только я вот чего не пойму. Что если я вместо такого

(defgeneric collide (x y))

(defmethod collide ((x asteroid) (y asteroid))
  ;;астероид сталкивается с астероидом
  )

(defmethod collide ((x asteroid) (y spaceship))
  ;;астероид сталкивается с космическим кораблем
  )
;;......
Напишу просто функцию, что-то вроде
(define (collide x y)
 (cond
   ((and (instance? x asteroid) (instance? y asteroid)) 
     ("астероид сталкивается с астероидом"))
   ((and (instance? x asteroid) (instance? y spaceship))
     ("астероид сталкивается с космическим кораблем"))
 ;;;..............
       ))
; И вызываю так
(collide asteroid asteroid)

То что от этого принципиально изменится? То есть я понимаю, что тут есть небольшой синтаксический сахарок, но речь не об этом. Заявляется обычно о том, что это какая то неимоверно мощная техника ООП, которая, чуть ли не затмевает собой все остальное. Например Legioner недавно заявил

Полиморфизм (времени выполнения) это сердце ООП. В этой связи, как ни странно, квинтэссенция ООП это мультиметоды

.

Я не спорю, я, вероятно, чего-то не понимаю. Пока я вижу только небольшой сахарок над «функция + ветвление». Хотелось бы увидеть пример применения, который не может быть выражен банальной конструкцией типа «функция + ветвление».

Иными словами, в чем сила?

Спасибо.

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

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

Конечно же имеют. Если монетка выпадает орлом с вероятностью 1/2, то значит она не может выпадать орлом всегда, или с вероятностью 0,3, или с вероятностью 0.001, или по какому-либо алгоритму. То есть это задает очень и очень жесткие ограничения на то, как монетка не может выпадать. Значит, определенность сильно повышается.

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

И, собственно, еще раз повторю. Твоя попытка в противоречие с хьюиттом наложить такие сильные ограничения на порядок доставки сообщений приводит к тому, что модель резко теряет свою универсальность. В варианте хьюитта (с неопределенным порядком) модель акторов может описывать любые системы, в том числе те, в которых порядок доставки фиксирован. Твоя же модель системы с фиксированным порядком описывать не может.

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

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

Одно дело, когда у нас есть четике инварианты (eg монетка может выпасть орлом или решкой — третьего не дано) и совсем другое — твои сопли о распределении вероятностей. Не путай.

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

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

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

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

Одно дело, когда у нас есть четике инварианты (eg монетка может выпасть орлом или решкой — третьего не дано) и совсем другое — твои сопли о распределении вероятностей. Не путай.

А мы не говорим о том, как монетка может выпасть. Мы говорим о том, как она выпадает на протяжении достаточно большой (потенциально бесконечной) выборки. Хьюитт говорит «может выпадать как угодно, может все время орлом, может все время решкой, может через раз, а может кодируя орлами двоичное представление числа пи». Ты же говоришь, что она должна выпадать вполне определенным образом с определенной вероятностью (0.5)

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

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

Ну раз он не обязательно должен быть разным, то, значит, может быть одинаковым? То есть в рассматриваемом случае - всегда 0. Или 1. Или 565646. Нет?

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

Ты же говоришь, что она должна выпадать вполне определенным образом с определенной вероятностью (0.5)

Я говорю что она должна выпадать с определенной вероятностью, но НЕопределенным образом. Короче отвали, ты заблудился в двух соснах. В модели Акторов нет никаких вероятностей, там есть только неопределенность. Обратись к другому специалисту.

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

Я говорю что она должна выпадать с определенной вероятностью,

А хьюитт говорит, что не должна

В модели Акторов нет никаких вероятностей

Ты уже сам среди себя определись, либо:

она должна выпадать с определенной вероятностью

либо:

В модели Акторов нет никаких вероятностей

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

Да, иначе это было бы ограничение, порождающее инварианты.

Если да, то о чем спор? Вот у меня «машина акторов» котора инкрементирует до получения 'stop, результат как ты сказал _может_ быть всегда одинаковым (иначе это накладывало бы ограничения) и вот она возвращает 0, 0, 0, 0 и так все время

чем эта машина акторов отличается от машины тьюринга, которая всегда возвращает 0? кто вообще тебе сказал что твоя машина акторов раелазиована внутри не как соовтетстующая МТ (допустим она в черном ящике и ты только можешь жать кнопку, получая на выходе 0 каждый раз)?

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

А хьюитт говорит, что не должна

Он вообще ничего не говорит о вероятностях

определись, либо:

Я говорил о вероятностях безотносительно модели Акторов, просто попытался говорить на твоем птичьем языке, чтобы указать, что ты попутал х с пальцем. Но ничего не вышло, извини.

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

и вот она возвращает 0, 0, 0, 0 и так все время

Это лишь частный случай. Там нет конкретного числа, оно неопределено, не важно, что там на самом деле выпадает.

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

Он вообще ничего не говорит о вероятностях

Правильно. Он нигде ограничений на вероятность не упоминает, значит их и нет. Значит никто не мешает актору все время возвращать один и тот же 0.

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

Значит никто не мешает актору все время возвращать один и тот же 0.

Никто не мешает, но это не определено, а в твоем случае — определено, и заранее известно, чуешь разницу?

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

Это лишь частный случай.

Ну да, ведь об этом и речь. актор - это же только модель, у нее есть много реализаций. И прелесть модели акторов в том, что она не накладывает чересчур сильных огарничений на реализацию - например одна реализация может все время возвращать 0 и она будет соовтетсвовать модели рассматриваемог онами актора. Другая всегда возвращает 1, третья - 55434, четвертая - как-то чередует числа, пятая - делает это случайно и т.д.

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

И вот для любой абсолютно «машины акторов» мы сможем написать машину тьюринга (и даже много разных машин) таких, что для них будут истины любые утвержедния выводимые для данной «машины акторов».

Отсюда сразу следует, что не может существовать ф-и, которая могла бы быть вычислена «машиной акторов» но не могла бы быть вычислена машиной Тьюринга.

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

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

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

Никто не мешает, но это не определено, а в твоем случае — определено, и заранее известно, чуешь разницу?

Ты понимаешь разницу между теорией и моделью (в плане метаматематики)? Вот «машина акторов» - это теория, а мт - это ее модель. У теории может быть много моделей, вообще говоря (так же как у спецификации может быть много реализаций, при этом они не обязательно в том или ином смысле эквивалентны).

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

У теории может быть много моделей

При этом чем меньше ограничений в теории, тем больше у нее будет моделей. И если теория корректна (soundness), то тогда из выводимости утвержедния следует его общезначимость (т.е. выводимое утверждение истинно на всех интерпретациях, иначе говоря, верно для всех моделей). Все непротиворечивые теории первого порядка soundness, более того - они еще и полны вдобавок (любое общезначимое утверждение выводимо).

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

Да нет, у Плоткина-то все хорошо, просто тот кусок текста (доказательство его) выдернут из контекста. Упоротый там хьюит. Он кстати сидит на LtU и регулярно срет. Отличился бтв не только историями про гипервычиления_в_акторах, еще рассказывает, что доказательство геделя о неполноте - оно неправильное, и на самом деле непротиворечивость математики изи доказывается в самой математике. Такие дела. Фрик от науки, короче.

Кстати, манера ведения дискуссий у него такая же как у анонимуса - аргументы собеседника он напрочь игнорирует, а на просьбу обосновать свои высеры просто как попка-дурак эти высеры повторяет. Тоже, видать, путает утверждение с его выводом.

вот то же самое впечатление

jtootf ★★★★★
()

Сила в модульности - ты можешь доопределить методы где-то далеко после того, как ты создал родовую функцию.

Плюс иногда можно с помощью around методов «патчить» функцию для уже существующих объектов. Но это только в том случае, если around метод ещё не занят. Хотя для этого мне больше нравится defadvice, который есть в Lispworks - http://www.lispworks.com/documentation/lw70/LW/html/lw-32.htm#pgfId-885978

Сверх того, ничего неимоверного, действительно, я не вижу.

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

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

кстати, че то подумал сейчас, если в языке есть интроспекция, можно это очень просто решить

collide := method(
   args := call evalArgs
   ""
)


add := method(
  collide = doString(
    Lobby getSlot("collide") code asMutable lexicalDo(
       atInsertSeq(findSeq("\n"), "\n" .. call message arguments at(0))
    ) 
  )
)


Asteroid := Object clone
SpaceShip := Object clone


add(if(args at(0) type == "Asteroid" and(args at(1) type == "Asteroid"))\
  then ("deal with asteroid hitting asteroid" println; return) )

add(if(args at(0) type == "SpaceShip" and(args at(1) type == "SpaceShip"))\
  then ("deal with spaceship hitting spaceship" println; return) )

add(if(args at(0) type == "SpaceShip" and(args at(1) type == "SpaceShip") and(args at(2) type == "Asteroid"))\
  then ("deal with spaceship hitting spaceship and asteroid" println; return) )

//////////////////////////////////////////////////////////////////////////////////////

collide(Asteroid clone, Asteroid clone) 
// deal with asteroid hitting asteroid


collide(SpaceShip clone, SpaceShip clone)
 // deal with spaceship hitting spaceship


collide(SpaceShip clone, SpaceShip clone, Asteroid clone) 
// deal with spaceship hitting spaceship and asteroid

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

если в языке есть интроспекция, можно это очень просто решить

Разумеется. Если к этому коду добавить поиск на совпадения (чтобы перезаписывать) и сортировку по специфичности, чтобы (add(if(args at(0) type == «Child» ...))) вставлялась раньше, чем (add(if(args at(0) type == «Super» ...))), то это и будут классические обобщённые функции.

Для аналога CLOS ещё надо реализовать :after, :before, :around, :metaclass, ... Ничего сложного, но в одну страничку кода уже не уложиться.

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

Хотя для этого мне больше нравится defadvice, который есть в Lispworks - http://www.lispworks.com/documentation/lw70/LW/html/lw-32.htm#pgfId-885978

Его можно и самому написать. Или даже просто использовать

(let ((old #'func))
  (fmakunbound 'func)
  (defun func (x y)
     ....
     (funcall old x y)
     ....))

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

и сортировку по специфичности, чтобы (add(if(args at(0) type == «Child» ...))) вставлялась раньше, чем (add(if(args at(0) type == «Super» ...))),

а это еще зачем? У нас ведь и так жеско прописаны все случаи.

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

У нас ведь и так жеско прописаны все случаи.

А, ещё хуже. Надо не «type ==», а что то вроде classof.

Чтобы

MyAsteroid := Asteroid clone

collide(SpaceShip clone, MyAsteroid clone)
тоже работало.

Обобщённые функции ведь тоже обязаны наследоваться.

А если они будут наследоваться, то

add(if(args at(0) type == "Asteroid" and(args at(1) type == "Asteroid"))\
  then ("deal with asteroid hitting asteroid" println; return) )

add(if(args at(0) type == "MyAsteroid" and(args at(1) type == "Asteroid"))\
  then ("deal with asteroid hitting my asteroid" println; return) )

collide(Asteroid clone, MyAsteroid clone)

и

add(if(args at(0) type == "MyAsteroid" and(args at(1) type == "Asteroid"))\
  then ("deal with asteroid hitting asteroid" println; return) )

add(if(args at(0) type == "Asteroid" and(args at(1) type == "Asteroid"))\
  then ("deal with asteroid hitting my asteroid" println; return) )

collide(Asteroid clone, MyAsteroid clone)

должны давать одинаковый результат.

А если порядок условий соответствует порядку ввода, то невозможно определить обобщённую функцию для наследника.

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

А как быть в такой ситуации

add(if(args at(0) typeof("MyAsteroid") and(args at(1) typeof( "Asteroid")))\
  then ("..."; return) )

add(if(args at(0) typeof("Asteroid") and(args at(1) typeof( "MyAsteroid")))\
  then ("..."; return) )
Какой тут приоритет должен быть? Тут разве нет противоречия?

somequest
() автор топика
Ответ на: комментарий от monk

добавить поиск на совпадения (чтобы перезаписывать)

Кстати, это не особо нужно, на самом деле. Совпадений н практике будет ничтожное количество, а добавление с ретурном (а я добавляю в начало ветвления) *семантически* и так перезапишет предыдущий случай, так как до него исполнение не дойдет просто. Расходами на память тут можно пренебречь. Это может понадобится только если нет выхода из ветки. Но на практике каждый раз проходить все ветки дорого, поэтому лучше не усложнять, и оставить как есть.

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

Какой тут приоритет должен быть? Тут разве нет противоречия?

http://www.lispworks.com/documentation/lw61/CLHS/Body/07_ffab.htm

Если вкратце, то сравнение происходит слева направо.

То есть для этих двух методов

MyAsteroid Asteroid -> 1
Asteroid MyAsteroid -> 2
MyAsteroid MyAsteroid -> 1

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

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

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

я добавляю в начало ветвления

В этом случае понятно. Но в нормальном необходима возможность наследования и, соответственно добавления методов в произвольном порядке.

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

необходима возможность наследования и, соответственно добавления методов в произвольном порядке.

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

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

но это противоречивая семантика, к тому же необоснованно сложная.

На самом деле достаточно логично. Если брать C++ с перегрузкой методов, то работает ведь также:

class asteroid {
  void collide(myAsteroid *x);
}

class myAsteroid  : A {
  void collide(asteroid *x);
}

ast = new asteroid()
myAst = new myAsteroid()

myAst.collide(ast) -> myAsteroid::collide(asteroid)
ast.collide(myAst) -> Asteroid::collide(myAsteroid)
myAst.collide(myAst) -> myAsteroid::collide(asteroid)

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

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

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

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

Пусть есть

;; asteroid.io
add(if(args at(0) typeof("MyAsteroid") and(args at(1) typeof( "Asteroid")))\
  then ("..."; return) )

;; myasteroid.io
import asteroid
...
add(if(args at(0) typeof("Asteroid") and(args at(1) typeof( "MyAsteroid")))\
  then ("..."; return) )

;; otherasteroid.io
import asteroid
...
add(if(args at(0) typeof("OtherAsteroid") and(args at(1) typeof( "Asteroid")))\
  then ("..."; return) )

;; client1
import myasteroid
import otherasteroid

collide (otherAsteroid clone, myAsteroid clone)

;; client2
import otherasteroid
import myasteroid

collide (otherAsteroid clone, myAsteroid clone)

В client1 и client2 один и тот же код даст разные результаты.

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

там все равно в каких-то случаях могут оказаться разные результаты, в том числе и с перезаписью. Поэтому, просто не нужно излишне усложнять.

somequest
() автор топика
Ответ на: комментарий от monk

Хотя для этого мне больше нравится defadvice, который есть в Lispworks - http://www.lispworks.com/documentation/lw70/LW/html/lw-32.htm#pgfId-885978

Его можно и самому написать. Или даже просто использовать

Можно, но с ограничениями. Там, где в данные уже вставлено #', он не сработает.

Даже и в этом случае остаётся зазор между «можно написать» и «уже написано». У меня в библиотеке есть ограниченная версия

https://bitbucket.org/budden/budden-tools/src/974ab6babbcd6600113bb90b2bb87d2...

но defadvice значительно лучше.

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