LINUX.ORG.RU

[haskell] есть ли что-то типа reflection? (недемократизм языка?)

 


0

0

Обычная фраза: deriving (Read, Show, Eq, Ord)

Компилятор умеет выводить инстансы этих typeclass-ов. А что делать, если хочется их выводить чуть-чуть по-другому или добавить еще один, который автоматически бы выводился? (Для этого, возможно, подошло что-то похожее на reflection, патчить компилятор не предлагайте)

__________________________________________________

Недемократизм языка в моем понимании -- это

1. Частичная реализация некой фичи и одновременно отстутствие инструмента для расширения реализации этой фичи. Например в яве оператор + для сложения целых, вещественных, строк и все: комплексные, кватернионы, вектора, матрицы... складывай уже через add.

2. Невозможность смены конкретной реализации фичи (зачастую связано с п.1). Например, невозможность создать в рамках с++ свой virtual dispatch (для того, что сделать множественный virtual dispatch, т.е. п.1). В принципе, п.2 до некоторой степени неизбежен, так как иногда намного проще сделать фичу, чем API для написания фич).

__________________________________________________

Более глобальный вопрос -- а насколько хаскель демократичен? (для обеспечения демократизма разрешается использовать ключи компилятора, template haskell, ...)

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

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

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

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

>Теперь в пользовательском коде мы можем написать просто find(42, vv), в то время как без статической типизации пришлось бы

>либо писать find_sorted_vector(42, vv)

>либо терять терять такты на проверку того, что вектор отсортирован

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

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

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

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

И вообще, язык высокого уровня абстрагируется от деталей поиска. Почему именно вдруг binary_search? А если vv у меня -- это вектор из short, и я для ускорения поиска ручками написал код с испольнованием SSE, где поиск *вовсе* не бинарный? Тогда тебе придется либо обманывать всех названием, либо везде переименовывать функцию на sse_search.

Тем не менее, проблема низкого уровня существует, но решать ее надо не так.

Например, когда мы пишем x["asdf"], но скобки означают дерганье сервера на другом конце земли со словариком, то это несколько не то, что бы хотелось.

Я бы предложил либо IDE подсвечивать такое, либо даже заменять на x.getFromServer("asdf").

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

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

а если у меня find(some_object, vv), причем поиск -- полиморфная функция, и алгоритм поиска определяется в рантайме? (хотя vv по-прежнему отсортирован)

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

> Страуструпа об этом подумал :-) Для совсем ленивых вот пример гетерогенного списка на плюсах без всяких void*

> http://www.linux.org.ru/jump-message.jsp?msgid=3697782&cid=3702496

Забавно, я, когда писал про войд думал о просто сях (или там тоже как-то можно без войдов), ибо на си++ по большому счету мне класть, ну а ты подумал о своем :). Как бы с помощью шаблонов можно много чего сделать, и лямбды, и карринг, и чего только нельзя, только это _считается_ костылями.

Использование боксинга для "эмуляции", "реализации" динамического общего типа, т.е. фактически тоже самое, что в хаскелле Data.Dynamic, мне не нравится. И кроме того, я тебе уже написал, динамическая - частный случай статической, дальнейшие споры тут бесполезны.

> Короче написать свой компилятор в лисп (без лексера и парсера, но л&п настолько тривиальны, что ими можно пренебречь). Да уж.

тот анонимус фигню сморозил - можно его не опровергать :)

> Я не против своих компиляторов, но это проект на 2-3-4 десятичных порядка более сложный, чем реализация (большей частью совсем не нужной) динамической типизации поверх статической.

В лиспе этого не надо, к примеру, обвесился declare, declaim - и ты в домике. Там _уже_ это работает, ничего делать не надо, а в некоторых реализациях еще и type inference есть.

> Все эти аннотации разумно выражать в виде *типа*.

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

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

либо писать find_sorted_vector(42, vv)

либо терять терять такты на проверку того, что вектор отсортирован

либо тащить вместе с вектором флаг isSorted, что опять тормозно и чревато увеличением кода (этот флаг должен проходить статически через систему типов)

Есть диспатч по типу (классу).

Пишется это ровно точно также, как и в сях.

(defmethod find-in-vector (x (v vector))                                                                                                                                          
  (do-generic-search x v))                                                                                                                                                                      
                                                                                                                                                                                  
(defmethod find-in-vector (x (v sorted-vector))                                                                                                                                   
  (do-binary-search x v))      

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

подумай сам где ты не прав

Честно говоря не знаю, вроде soft typing, вроде динамический язык. Что не так?

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

> До появления шаблонов в плюсах мы действительно были ограничены, вот лисперы-анабиозники пока эту новость (о неограниченности) и не просекли.

К сожалению, си++ мне в данный момент совершенно не интересен. Да и даже в контексте дискуссии - он не сильно хороший пример, ибо у него достаточно слабая система типов (как минимум нет ни автоматического вывода, ни ADT или чего-то подобного). Лучше все-таки будут смотрется хаскелль, мл, скала.

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

> Забавно, я, когда писал про войд думал о просто сях (или там тоже как-то можно без войдов), ибо на си++ по большому счету мне класть, ну а ты подумал о своем :). Как бы с помощью шаблонов можно много чего сделать, и лямбды, и карринг, и чего только нельзя, только это _считается_ костылями.

Что там считают костылями анабиозники, для которых статическая типизация -- это си, никому не интересно.

> В лиспе этого не надо, к примеру, обвесился declare, declaim - и ты в домике. Там _уже_ это работает, ничего делать не надо, а в некоторых реализациях еще и type inference есть.

1. и ты после declare, declaim будешь называть типизацию лиспа динамической?

2. как там у declare, declaim с экзистенциональными типами?

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

> И код, который использует эти функции, совершенно спокойно оптимизируется компилятором. В чем проблема?

Как он у тебя оптимизирует, если у тебя нет соответсвующей аннотации -- а именно, "данная функция принимает аргументом только сортированный вектор". Если же аннотация имеется, то язык нельзя назвать динамически типизированным, во всяком случае *здесь* ты используешь его статически типизированное подмножество.

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

> К сожалению, си++ мне в данный момент совершенно не интересен. Да и даже в контексте дискуссии - он не сильно хороший пример, ибо у него достаточно слабая система типов

и при своей достаточно слабой системе типов он умеет гетерогенные списки и аналог (make-instance (read))

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

>Страуструпа об этом подумал :-) Для совсем ленивых вот пример гетерогенного списка на плюсах без всяких void*

(make-instance (read)) это не диспатч. Вернее, может и диспатч, но не по типу, а по EQL. Ты это через свою убогенькую перегрузку не сделаешь.

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

> Использование боксинга для "эмуляции", "реализации" динамического общего типа, т.е. фактически тоже самое, что в хаскелле Data.Dynamic, мне не нравится.

почему? ведь *фактически на уровне байтов* она именно так (я про с++ говорю, не про Data.Dynamic) и реализуется в лиспе, разве что боксом могут быть не 4 байта, а 2 бита + 4 байта.

> И кроме того, я тебе уже написал, динамическая - частный случай статической, дальнейшие споры тут бесполезны.

Господин Иегова, простите, не узнал Вас.

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

Тебе либо придется делать аннотации типов, либо юзать type inference, который без аннотаций неразрешим ЕМНИП при F_{2<:}

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

Это только через void* (и аналоги) и разнообразные костыли, типо Boxed с тайптегом и/или табличкой типов, фактически убирающие статику и эмулирующие динамику.

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

>во всяком случае *здесь* ты используешь его статически типизированное подмножество.
Ого, какой прыткий. У него soft typing уже статика :))

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

> (make-instance (read)) это не диспатч. Вернее, может и диспатч, но не по типу, а по EQL. Ты это через свою убогенькую перегрузку не сделаешь.

Если ты неослили плюсы, то это твои проблемы. Иначе доказывай, почему в плюсах это невозможно.

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

> Ого, какой прыткий. У него soft typing уже статика :))

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

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

> "Профит" там только возможность большей оптимизации.

Ну что, один профит таки обнаружился. Но он отнюдь не "только".

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

> Это только через void* (и аналоги) и разнообразные костыли, типо Boxed с тайптегом и/или табличкой типов, фактически убирающие статику и эмулирующие динамику.

Именно *таковы* рантаймовые кишки любого вашего лиспа, исполнящего программу с динамикой (1). И чем ты не доволен?

(1) за исключением экзотических аппаратных платформ с тэгами для памяти.

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

Лиспом то я доволен.
А на C++ это выглядит как говно, работает как говно, и абсолютно небезопасно во всех смыслах.
Не надо вот говорить, что void* это такая обубенная возможность статической типизации, превращающая ее в динамическую.

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

> Лиспом то я доволен. А на C++ это выглядит как говно, работает как говно, и абсолютно небезопасно во всех смыслах. Не надо вот говорить, что void* это такая обубенная возможность статической типизации, превращающая ее в динамическую.

Острая форма дислексии? Где в моем примере гетерогенного списка юзается void* ?

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

>Система типов Хиндли-Милнера (в которой вывод типов именно что выводит всё и всегда) уже весьма богата.

Какой будет тип у функции с переменным количеством аргументов, у функции возвращающей переменное количество значений?

>Если мы хотим типы высших порядков - аннотировать нужно только их,

И конечно же тут логические ошибки невозможны.

>и динамика на таких примерах сдохнет совсем.

опенсорс.орг.ру намекает, что нужно ссылку на проект, который дохнет от ошибок динамики.

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

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

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

>Какой будет тип у функции с переменным количеством аргументов, у функции возвращающей переменное количество значений?
Он сейчас что-нибудь ляпнет про карринг, вот гарантирую :))

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

Ах ну да, и помогает корову с комплексным числом не сложить :))
(в динамических языках это решается, на самом деле, банально префиксом, "cow+" и "+" соответственно. Про обфускацию в C++ стиле верно выше заметили)

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

>Если ты неослили плюсы, то это твои проблемы. Иначе доказывай, почему в плюсах это невозможно.
У плюсофилов как всегда мания величия помноженная на неграмотность и некомпетентность...

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

>1. и ты после declare, declaim будешь называть типизацию лиспа динамической?

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

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

>и при своей достаточно слабой системе типов он умеет гетерогенные списки и аналог

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

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

> Что там считают костылями анабиозники, для которых статическая типизация -- это си, никому не интересно.

Для меня статическая типизация, как я уже сказал - это хаскелл, *мл, скала, но никак не си++

> 1. и ты после declare, declaim будешь называть типизацию лиспа динамической?

Да, иди кури, что такое динамическая типизация. Что untyped lambda calculus и чем оно отличается от typed lambda calculus. И чем отличаются классы значений (в динамических языках) от типов (в типизированных языках).

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

> Как он у тебя оптимизирует, если у тебя нет соответсвующей аннотации -- а именно, "данная функция принимает аргументом только сортированный вектор". Если же аннотация имеется, то язык нельзя назвать динамически типизированным, во всяком случае *здесь* ты используешь его статически типизированное подмножество.

Нет, это не статически типизированное подмножество.

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

> и при своей достаточно слабой системе типов он умеет гетерогенные списки и аналог (make-instance (read))

Через динамик каст, ага :) Но не имеет, как я уже сказал - ни ADT, ни вывода типов.

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

> почему? ведь *фактически на уровне байтов* она именно так (я про с++ говорю, не про Data.Dynamic) и реализуется в лиспе, разве что боксом могут быть не 4 байта, а 2 бита + 4 байта.

Нет. Там нет боксинга - в принципе. Там все по другому - как минимум каждая переменная имеет обобщенный тип T или dyn, и только потом ее _класс ее значений_ (хоть он и называется типом в динамически-типизированном языке, он таковым не является и сильно отличается от типа в статически типизированном языке) уточняется с помощью аннотаций и автоматического вывода, компилятор определяет либо она принимает значения только integer, либо (or integer string), либо (integer 3 45), либо (or num symbol), либо (vector * *).

Потом на основании полученных результатов компилятор оптимизирует код - посмотри на (disassemble 'factorial) - нет там никаких 2бита + 4 байта, и, если были какие-то ошибки - кидает варнинги и ерроры.

> Господин Иегова, простите, не узнал Вас.

Хочешь поспорить с робертом харпером, профессором карнеги меллон, получившим награду за исследование системы типов? Ты вообще читал мое сообщение? - это аргумент в твою пользу, а не в мою, и ты от него отказываешься?

> Тебе либо придется делать аннотации типов, либо юзать type inference, который без аннотаций неразрешим ЕМНИП при F_{2<:}

Кто тебе сказал, что в схеме и эрланге будет System F_? Тем более, что F - для typed lambda calculus, а у нас untyped lambda calculus. И, кстати, почему-то хаскеллю не мешает неразрешимость (если использовать некоторые расширения языка) :) (да я знаю почему не мешает :)).

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

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

Это широкораспространенное заблуждение. Можешь не приводить здесь слова из википедии - там как всегда написана чушь.

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

> Система типов Хиндли-Милнера (в которой вывод типов именно что выводит всё и всегда) уже весьма богата.

Но ведь есть же системы типизации и побогаче? :) И которые тоже всегда выводятся :)

> Если мы хотим типы высших порядков - аннотировать нужно только их, и динамика на таких примерах сдохнет совсем.

Суть в том, что как раз-таки не сдохнет, в отличие от :)

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

и при своей достаточно слабой системе типов он умеет гетерогенные списки и аналог

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

Подозреваю дислексию. Последние 8 строк кода толсто намекают, как сделать самому typecase. Можно даже макросы написать для

TYPECASE x[i] // value -- это новое имя для x[i], захардкожено
  CASE int THEN int z=value+12; std::cout<<z;
  CASE double THEN float y=1/value; std::cout<<y;
  CASE Hierarhy1 THEN std::cout<<"Hierarhy1";
  ELSE std::cout<<"unknown";
END
www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> Для меня статическая типизация, как я уже сказал - это хаскелл, *мл, скала, но никак не си++

иди тогда обсуждай свои вопросы с такими же альтернативно одаренными

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

>> Система типов Хиндли-Милнера (в которой вывод типов именно что выводит всё и всегда) уже весьма богата.

> Но ведь есть же системы типизации и побогаче? :) И которые тоже всегда выводятся :)

Какие конкретно?

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

>> почему? ведь *фактически на уровне байтов* она именно так (я про с++ говорю, не про Data.Dynamic) и реализуется в лиспе, разве что боксом могут быть не 4 байта, а 2 бита + 4 байта.

> Нет. Там нет боксинга - в принципе. ......

непоняяяяял... а как гетерогенные списки в лиспе делаются? тоже без боксинга и без "void* (и аналоги) и разнообразные костыли, типо Boxed с тайптегом и/или табличкой типов, фактически убирающие статику и эмулирующие динамику"?

> Потом на основании полученных результатов компилятор оптимизирует код - посмотри на (disassemble 'factorial) - нет там никаких 2бита + 4 байта, и, если были какие-то ошибки - кидает варнинги и ерроры.

А для этого мой боксинг и думаю Data.Dynamic тоже не предназначены.

> Хочешь поспорить с робертом харпером, профессором карнеги меллон, получившим награду за исследование системы типов? Ты вообще читал мое сообщение? - это аргумент в твою пользу, а не в мою, и ты от него отказываешься?

Я сообщение прочитал с точностью до наоборот. Все же жаль, что анонимусов различать нельзя.

Зачем ты его писал мне (я его тут разжевываю всем), а не анонимусам?

> Кто тебе сказал, что в схеме и эрланге будет System F_? Тем более, что F - для typed lambda calculus, а у нас untyped lambda calculus. И, кстати, почему-то хаскеллю не мешает неразрешимость (если использовать некоторые расширения языка)

Если твои инференс даст что-то слабее F_{2<:}, то я сомневаюсь в его практической пользе.

Давай-ка выскажись конструктивно, какую систему ты собрался выводить? И совсем без аннотаций? Без них даже хаскелисты обойтись не могут.

И если с аннотациями, то почему ты будешь считать свое изделие с динамической типизацией, а не с soft typing хотя бы?

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

> даже и не знаю как это можно 'аткаментиравать.

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

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

> Для меня статическая типизация, как я уже сказал - это хаскелл, *мл, скала, но никак не си++

Несмотря на всю бредовость твоего высказывания, оно меня подвигло на мысль -- для освоения скалы написать гетерогенные списки на ней.

ЕМНИП там в скале у всех типов есть общий предок, не? Тогда гетерогенные списки на скале будут не так убедительны, как на С++, где такового предка нет.

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

Ну и как же ты без типов в рантайме динамическую типизацию устроишь? :)

Динамическая типизация это именно то, что значения в рантайме имеют типы.
И какое же, интересно, альтернативное определение у анонимных экспертов с ЛОРа?

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

> Ну и как же ты без типов в рантайме динамическую типизацию устроишь? :)

Никак, просто формулировка неправильна, хотя бы потому, что "значение" переменной в статике тоже _имеет тип_, т.е. ты не можешь сделать так 123 + "FOO".

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

> Несмотря на всю бредовость твоего высказывания, оно меня подвигло на мысль -- для освоения скалы написать гетерогенные списки на ней.

Чего ради? Их можно сделать на скале, хочешь ссылку дам? :). Единственное, что я хотел донести "этим бредовым высказыванием", - это то, что не во всяком языке со статической типизацией можно реализовать эмуляцию динамической типизации средствами самой этой системы типизации, без использования "костылей" - вроде указателей или dynamic_cast и метапрограммирования, хотя по большому счету static type system должна позволять это сделать - принципиально (например, языки, в которых это можно сделать - haskell, *ml, *scala и др).

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

>В которых элементом может быть объект любого типа.

Ээээ. Вообще любого?

Если так, то тут языки со статической типизацией не рулят. Но какой смысл в списках, элементы которых могут быть _любым_ типом?

Да и всегда ли есть требование, чтобы тип был _любой_?

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