LINUX.ORG.RU

баг или фича

 , джон маккарти


1

1

Почитываю на досуге книжку «Интерпретация лиспа и scheme», Кристиана Кеннека, и обнаружил любопытную фразу:

Под влиянием лямбда-исчисления, в честь которого названа специальная форма lambda, LISP-1.0 был сделан динамическим, но вскоре Джон Маккарти осознал,что он ожидал получить от следующего выражения (2 3), а не (1 3):

(let((a 1))
((let((a 2))(lambda(b)(list a b)))
3))
Эта аномалия (неосмелюсь назвать её ошибкой)была исправлена введением новой cпециальной формы function. Она принимала lambda-форму и создавала замыкание...

В связи с этим сразу 2 вопроса:

1) Почему лямбда исчисление здесь ассоциируется с динамическим связыванием, а не лексическим, как сейчас принято считать в мейнстриме?
2) Почему автор считает это аномалией (и это мнение я вижу вообще часто в различных источниках), когда это совершенно нормальное поведение для динамического связывания. What a fucking «аномалия», это что как если бы НЛО прилетело? Неужели Маккарти был настолько туп, что это казалось ему «аномалией»?



Последнее исправление: cetjs2 (всего исправлений: 3)

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

Это не RAII, а имитация. RAII говорит о том, что объект захватывает ресурс и отвечает за его освобождение. Твой костыль так не работает. Shared_ptr на нем не сделаешь.

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

они являются свойством метаязыка. да, и так и эдак реализуются — но один способ проще, другой сложнее. ИМХО, способ с разными пространствами проще.

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

ок, а как тогда их измерять? в чем качество состоит? какие у него метрики? и почему ты считаешь, что метрики стандарта — на качество стандарта и реализации стандарта, то есть языка — не влияют?

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

в-нулевых, чем не нравится макрос with с unwind-protect? ещё без объектов. в начале захватывает ресурс, делает тело, в конце через unwind-protect — освобождает. эффект аналогичный RAII, только на unwind-protect.

во-первых, что там у всех объектов в лиспе — нам пофиг, если в нашем «металиспе» есть пространство имён для объектов лисп-4, в котором можем сделать так, как захотим. в том числе, сделать так, чтобы время жизни объектов из лисп-4 начиналось с блока активации, а заканчивалось в этом блоке, реализуя подсчёт ссылок, например. локальный объект по окончанию блока прибивался бы. при этом для глобальных понадобились бы какие-то спец.формы, например гипотетические defglobalobject, для локальных — with-object ... , устроенная аналогично тому макросу with: unwind-protect, в начале которого объект создаётся и инициализируется, счётчик ссылок++, по окончанию — счётчик ссылок--, и если 0, финализируется и прибивается. вот этот инициализатор такого особого объекта перекрывается и делает захват ресурса в RAII, финализатор — освобождает ресурс.

весь вопрос в том, чтобы финализатор вызывался детерменированно, что для «всех объектов в лиспе» по дефолту не так, ну а для особых ведь можно сделать так, как захотим?

во-вторых, какая задача решается? начали с реализации finally в try-except-finally, потом ты зачем-то перескочил на Shared_ptr (зачем он в лиспе, когда указателей нет, есть привязки?)

я говорю, что тот же finally можно реализовать аналогично with через unwind-protect.

в-третьих, действительно, что мешает сделать защёлку с необратимым переходом ? чтобы эта защёлка устанавливалась только на начале «блока активации», сбрасывалась только по окончанию, и не менялась внутри блока? «объект, который захватывает ресурс» — это блок активации. однозначно соответствует спец. формам: начало блока активации — с гипотетического defglobalobject или with-local-object, окончание блока активации — конец текущего модуля если начали с defglobalobject или конец with-local-object, если начали с него.

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

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

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

смысл 10-го пространства, со спец. формами в том числе и в расширении фаз произвольным способом.

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

С unwind-protect есть проблемка в виде call-with-current-continuation. Но она по идее решается запретом на её неадекватное использование.

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

эффект аналогичный RAII, только на unwind-protect

ну ты даешь, совсем обнаглел

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

Они отличаются и достаточно существенно, ибо ортогональны структурам данных.

Они никак не отличаются, потому что одно из другого делается достаточно тривиальным _синтаксическим_ преобразованием. Есть классы - значит есть и классы типов, есть классы типов - есть и классы.

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

ИМХО, способ с разными пространствами проще.

Какой способ? Речь о том, как эти разные пространства реализовывать. Можно весьма просто макросом на 20 строчек. А можно - кривым хаком компилятора.

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

Шел 2013 год, необразованные дебилы раз за разом вспоминали давным-давно решенные проблемы.

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

Есть классы - значит есть и классы типов, есть классы типов - есть и классы.

Нет. Тайпклассы можно сравнить разве что с интерфейсами, да и то весьма условно. В Haskell нет аналогов ОО-классов, а в ОО-языках обычно нет полноправных аналогов тайпклассов(можно сделать, например, через интерфейсы+дженерики, а в С++, через классы, шаблоны и CRTP/Barton–Nackman).

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

Нет. Тайпклассы можно сравнить разве что с интерфейсами

Об этом и речь. Никакой разницы между ними нет.

В Haskell нет аналогов ОО-классов, а в ОО-языках обычно нет полноправных аналогов тайпклассов

С чего ты взял? Как же все исполдьзуют тайпклассы в ООП языках и интерфейсы в хаскеле, если их там нет?

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

Так покажи код-то. Иерархия «классов» + фабрика. Например, создающая объект по имени класса.

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

Никакой разницы между ними нет.

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

Как же все исполдьзуют тайпклассы в ООП языках

Покажи.

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

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

Конечно, нет.

Покажи.

Любое использование интерфейса - это использование тайпкласса. Ведь это одно и то же.

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

Иерархия «классов»

Нету никакой иерархии.

Иерархия «классов»

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

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

Любое использование интерфейса - это использование тайпкласса. Ведь это одно и то же.

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

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

Нету никакой иерархии.

А в ООП есть.

Что ты подразумеваешь под «фабрикой»?

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

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

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

class Factory where make :: a1 -> ... -> an -> c

Пожалуйста.

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

А в ООП есть.

Не обязательно. Подтипирование ортогонально ООП.

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

Ты это так и не показал.

Я не совсем понимаю что надо показать. Укажи конкретный пример, где тайпклассы и интерфецсы отличаются друг от друга.

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

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

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

А где тут создание объектов?=) Я так понимаю, именно этого от вас и ждут.

Вообще, скорее прав(пусть и не во всем) другой анон, а не вы.

Вот хорошее описание. Думаю вам обоим(или вас тут больше?) будет полезно.

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

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

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

Haskell's objects don't carry run-time type information. Instead, the class constraint for a polymorphic operation is passed in as a «dictionary» implementing all operations of the class

И чем это отличается от обычного позднего связывания? правильно! Ничем - это и есть обычное позднее связывание.

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

Тебя просили(как я понял), показать код создания объекта по имени класса. В любом ООП-языке ты спокойно создашь метод, возвращающий интерфейс, который анализирует данные и создает объект нужного класса. Просто покажи такой метод на Haskell.

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

Текст по ссылке писал полный баран

Извини, пока ты не докажешь свою позицию, я не вижу причин так отзываться об авторе текстов на haskell.org.

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

Это ты забыл, что не пишут на сишке, как на хаскеле, а на хаскеле, как на сишке. Потому что это бессмысленно.

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

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

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

Тебя просили(как я понял), показать код создания объекта по имени класса.

При чем тут ООП? Это рефлексия, ортогональное ООП понятие.

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

Конечно, не в любом.

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

Извини, пока ты не докажешь свою позицию, я не вижу причин так отзываться об авторе текстов на haskell.org.

Я же не про всех авторов - а про одного конкретного. Который напрямую врет. Ну может не баран - пиздабол.

Это ты забыл, что не пишут на сишке, как на хаскеле, а на хаскеле, как на сишке. Потому что это бессмысленно.

Нет, я ничего не забыл. Просто автор говорит типа «смотрите как все пиздато на хаскеле и как плохо на сишке», хотя можно на сишке как на хаскеле.

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

Это отличается от объектно-ориентированного программирования

Чем?

Ты путаешь возможность эмуляции(тайпклассов в ОО-языке и ООП в Haskell), которая действительно есть, с тождественностью(якобы) этих концепций.

Так речь не об эмуляции а именно о том, что это одно и то же. Тайпклассы - те же интерфейсы, то есть ООП.

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

Это рефлексия, ортогональное ООП понятие.

Да не дошли мы еще до рефлексии.

shared_ptr<IA> make(const string &name)
{
     if (name == "aaa") {
          return make_shared<A>();
     }
     else (name == "bbb") {
          return make_shared<B>();
     }
     return shared_ptr<IA>(); // nullptr
}

не в любом.

Ну если к ОО-языкам относить Haskell'и и др., то действительно не в любом=)

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

это одно и то же. Тайпклассы - те же интерфейсы

Вот простейший пример(по той ссылке, кстати):

class Foo a where
  foo :: a -> String
 
instance (Num a) => Foo a where
  foo _ = "Num"
 
instance Foo Int where
  foo _ = "int"
 
f :: (Num a) =>  a -> String
f = foo
 
main = do print (foo (1::Int))
          print (f (1::Int))

Что будет напечатано и почему. И почему интерфейсы/классы в ОО-языках вели бы себя тут иначе? С чего ты вообще взял, что это одно и то же?

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

С чего ты вообще взял, что это одно и то же?

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

Вот простейший пример(по той ссылке, кстати):

И что он показывает?

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

Что-то ты все код не выкладываешь и не выкладываешь...

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

Ну и твой пример один в один переписывается.

Хм. Возможно я слишком плохо знаю Haskell. Перепиши один в один, пожалуйста.

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

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

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

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

Начиная с того, что не бывает двух тайпклассов с одинаковыми методами, но интерфейсы с одинаковыми методами - явление рядовое

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

и заканчивая тем, что объекты не привязаны к своим тайпклассам, но привязаны к интерфейсам.

С чего ты взял, что не привязаны? В той же джаве, например, тайпклассы привязаны. Это зависит от реализации.

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

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

В Java нет тайпклассов. Ты вообще какой-то странный. Если можно взять две концепции и выделить между ними общее, объявив отличия разницей реализаций, то это еще не значит, что это одна концепция.

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

Тайпклассы и интерфейсы являются способом описания операций над объектом(или группой объектов, в случае тайпклассов). Но они сильно отличаются друг от друга.

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

В Java нет тайпклассов.

Как это нет? Как же все их исопльзуют, если их там нет?

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

Что же тогда можно объявить «одной концепцией»?

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

Но они сильно отличаются друг от друга.

Разные реализации ООП отличаются друг от друга не меньше. Иногда даже больше.

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

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

Это сделает нерабочими тонны ОО-кода. Это заставит людей называть методы с оглядкой на то, что возможны конфликты. На выразительность это повлияет как раз тем, что лишит тебя возможности произвольного именования.

С чего ты взял, что не привязаны?

Это просто факт для Haskell.

В той же джаве, например, тайпклассы привязаны. Это зависит от реализации.

Не надо пытаться выдать тезис, который доказываешь, за доказательства этого тезиса. Тайпклассы и ОО-интерфейсы решают похожие проблемы, они пересекаются по возможностям. Но они не тождественны. Ты еще не доказал, что в Java есть тайпклассы. Начать можешь с демонстрации простых тайпклассов на Java. Например, с Functor:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

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

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

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

Это сделает нерабочими тонны ОО-кода.

И что? Это сугубо синтаксический аспект. Любое синтаксическое изменение сделает нерабочим тонны ОО-кода.

Это просто факт для Haskell.

Для хаскеля - да. Для тайпклассов - нет.

Но они не тождественны.

В чем нетождественность?

Ты еще не доказал, что в Java есть тайпклассы.

Ты еще не доказал что это не одно и то же.

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

Я же сказал - 1в1. Ничего переводить не надо.

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

Как это нет? Как же все их исопльзуют, если их там нет?

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

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