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 недавно заявил

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

.

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

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

Спасибо.

Ты ручками реализовал мультиметоды. Ты и полиморфизм можешь так написать. Полиморфизм/мультиметоды это концепция, а не языковая конструкция. Паттерн. Как он конкретно реализован, это дело второе. В твоей реализации с instance? проблем много, думаю ты и сам это понимаешь, лучше когда язык поддерживает такие паттерны без дополнительных усилий. Но если не поддерживает — можно и без поддержки жить. В том же C полиморфизм используется практически во всех крупных проектах в той или иной степени.

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

В твоей реализации с instance? проблем много, думаю ты и сам это понимаешь

Не совсем понимаю. Если речь идет о каком то конкретном языке, может там и есть какие-то проблемы. Но в общем-то, никаких проблем не вижу.

somequest ()

То что от этого принципиально изменится?

Принципиально изменится расширяемость. Вот появился у тебя корабль, который сталкивается с астероидом по другому

(in-package :strongship)
(defclass strongship (space:spaceship) ())

И для обобщённой функции достаточно определить методы для этого корабля

(defmethod space:collide ((x space:asteroid) (y strongship))

  )

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

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

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

Проблема одна: расширяемость. Если заведомо известно, что классы asteroid и spaceship окончательные (final в терминах Java) и новых сталкивающихся объектов не появится, то вариант с cond лучше, так как быстрее работает

monk ★★★★★ ()

Хотелось бы увидеть пример применения, который не может быть выражен банальной конструкцией типа «функция + ветвление».

Хотелось бы увидеть алгоритм, который не может быть реализован на машине Тьюринга.

/fixed

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от somequest

Что ты будешь делать если тебе надо кроме asteroid и spaceship добавить возможность столкновения еще с каким-либо объектом?

anonymous ()

Обобщённые функции - основа для комбинаторов методов.

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

И для обобщённой функции достаточно определить методы для этого корабля

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

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

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

somequest ()
Ответ на: комментарий от no-such-file

Хотелось бы увидеть алгоритм, который не может быть реализован на машине Тьюринга.

Интересный вопрос. И вопреки твоим ожиданим, такие алгоритмы есть. Вот простой пример.

Допустим, у нас есть актор, который посылает сам себе сообщение add и stop. Если приходит add, он инкрементирует счетчик, если stop — то останавливается, если получено сообщение add, то актор снова посылает себе сообщение add. Сколько идут сообщени — неизвестно, известно только то, что если сообщение отправлено — оно рано или поздно будет получено. На МТ данный алгоритм нереализуем, сынок.

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

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

С помощью [одного лишь] ветвления по типам невозможно реализовать динамическую диспетчеризацию с делегированием.

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

С помощью [одного лишь] ветвления по типам невозможно реализовать динамическую диспетчеризацию с делегированием.

Ровно это утверждение применимо и к обобщённым функциям. Обобщённая функция (по своему определению) реализует динамическую диспетчеризацию по комбинации классов своих аргументов.

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

С помощью [одного лишь] ветвления по типам невозможно реализовать динамическую диспетчеризацию с делегированием.

Расскажи это создателям процессоров, на которых всё ваше замечательное ООП крутится. В системе команд процессора нет никакого ООП, никакой функциональщины, акторов с методами и пр.

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

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

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

Допустим, у нас есть актор, который посылает сам себе сообщение add и stop. Если приходит add, он инкрементирует счетчик, если stop — то останавливается, если получено сообщение add, то актор снова посылает себе сообщение add. Сколько идут сообщени — неизвестно, известно только то, что если сообщение отправлено — оно рано или поздно будет получено. На МТ данный алгоритм нереализуем, сынок.

Вообще-то это банальнейшая state machine которая даже на ассемблере пишется левой ногой за пять минут.

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

с абсолютно таким же результатом можно написать на банальной сишечке, например

Можно. GObject ведь написали. Но реализация диспетчеризации там не через ветвления.

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

Но реализация диспетчеризации там не через ветвления.

Есть 100500 способов реализовать диспетчеризацию вообще-то. Зависит только от фантазии.

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

Возможно на асме ты это и напишешь, но речь шла конкретно об МТ.

А смысл вести речь конкретно об МТ? Софт работает не на МТ а на конкретных железках.

Чисто теоретические вопросы, конечно, интересны, но часто совершенно бессмысленны.

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

Возможно на асме ты это и напишешь, но речь шла конкретно об МТ

ОХ ЛОЛ, не надо так, я чуть чаем не подавился.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

Это не то. Я описал задачу не совсем точно, видимо. Точней будет так. В самом начале актор посылает себе 2 сообщения: add и stop, а затем уже все дальше по тексту. Важное замечание: все сообщения асинхронные, никаких ограничений на порядок получения сообщений нет, никакой синхронизации между отправкой и получением нет. Например,

actor sendMessageTo(self, stop)
actor sendMessageTo(self, add)

...running

>>stop message reseived. value is 3

actor sendMessageTo(self, stop)
actor sendMessageTo(self, add)

...running

>>stop message reseived. value is 10

actor sendMessageTo(self, stop)
actor sendMessageTo(self, add)

...running

>>stop message reseived. value is 0

Так примерно должно работать

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

В самом начале актор посылает себе 2 сообщения: add и stop, а затем уже все дальше по тексту. Важное замечание: все сообщения асинхронные, никаких ограничений на порядок получения сообщений нет

Это эквивалентно следующей задаче: выполняем инкремент в цикле и через рандомное количество итераций выходим. Легко реализуется.

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

Мы все еще о машине тьюринга говорим? Ты знаешь что это такое?

somequest ()
Ответ на: комментарий от no-such-file

это псевдорандом.

Это означает, что ты не можешь реализовать данный алгоритм, так как псевдорандом эквивалентен предусловию. Зачем он тогда тебе вообще нужен? пиши тогда не

выполняем инкремент в цикле и через рандомное количество итераций выходим

а

выполняем инкремент в цикле и через (пред)определенное количество итераций выходим

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

На МТ данный алгоритм нереализуем, сынок

Я описал задачу не совсем точно, видимо

Ты уж как-то определись, это алгоритм, или только описание.

no-such-file ★★★★★ ()
Ответ на: комментарий от somequest

На МТ данный алгоритм нереализуем, сынок.

С чего бы это? Элементарно пишется на той же akka, например.

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

Возможно на асме ты это и напишешь, но речь шла конкретно об МТ.

Но на асме нельзя написать то, что нельзя написать на МТ.

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

В самом начале актор посылает себе 2 сообщения: add и stop, а затем уже все дальше по тексту. Важное замечание: все сообщения асинхронные, никаких ограничений на порядок получения сообщений нет, никакой синхронизации между отправкой и получением нет. Например,

изи бризи:

#lang racket

(define thd
  (thread (λ ()
            (define counter 0)
            (let loop ()
              (match (thread-receive)
                ['add (set! counter (add1 counter))
                      (thread-send thd 'add)
                      (loop)]
                ['stop (displayln (~a "stop message received, value is " counter))])))))

(thread-send thd 'add)
(thread-send thd 'stop)

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

Нет. Это абстракция, которая написана на чем угодно, хоть на самой модели Акторов. Смысл в том, что то что можно в модели Акторов — невозможно на МТ, например.

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

Смысл в том, что то что можно в модели Акторов — невозможно на МТ, например.

Почему невозможно, если есть реализация выше? Что именно из описанного тобой невозможно в мт?

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

модели Акторов

Модель Акторов - абстракция.

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

если есть реализация выше?

Какая реализация? Ты не путай реализацию в вакууме с реализацией конкретно на МТ. Ты еще непиши реализацию на Акторах, а потом доказывай, на этом основании что реализация на МТ возможна.

Что именно из описанного тобой невозможно в мт?

Орбитр. В модели Акторов есть абстракция арбитра, которая допускает неограниченный индетерминизм. Именно это позволяет говорить нам о том, что порядок отправки сообщений не влияет на порядок их приема.

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

Какая реализация? Ты не путай реализацию в вакууме с реализацией конкретно на МТ.

Выше реализация на МТ через треды.

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

Но она не допускает. Никакая задача которая бы не решалась МТ акторами не решается. Если это не так - пруф такой задачи. То что ты выше описал на мт выражается совершенно тривиальным образом.

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

через треды

Кстати, может я ошибаюсь, но по-моему треды на МТ тоже не реализуемы. Чтобы были треды, нужны прерывания, которых на МТ тоже нет. Там конечно возможно что-то типа имитации тредов, когда прерывание каждой из задач заранее запланированно как бы, но это немного не то.

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

Кстати, может я ошибаюсь, но по-моему треды на МТ тоже не реализуемы.

С чего ты взял?

Чтобы были треды, нужны прерывания, которых на МТ тоже нет.

Нет, не нужны.

когда прерывание каждой из задач заранее запланированно как бы

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

anonymous ()

если коротко то google://expression problem

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

То что я выше описал вообще не решается на МТ.

Еще раз - выше приведена реализация на МТ того, что ты написал. Т.о. факт того, что эта задача решается на МТ - _формально строго доказан_.

Возможно, ты был неточен и описал какую-то не ту задачу. Тогда опиши нужную (которая на МТ решаться не будет).

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

Допускает.

Можно пруфы? Где можно увидеть формальное описание модели, формализацию свойства индетерменизма и математическое доказательство того, что эта модель обладает указанным свойством?

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