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, ...)

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

> Там нет проблем, потому что есть Template Haskell.

Там нет проблем с отступами, потому что всё, что пишется с отступами, можно писать без них. TH тут ни при чём.

> при _тупой_ подстановке, как предлагал ОП, много чего может поламаться.

Естественно.

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

> Ну и кроме того, я не вижу особой необходимости в статической типизации

Бывает. Некоторые умудряются таки промыть очки.

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

> даже варнинг не выдает

Выдаёт, с соответствующим флагом компилера.

> несмотря на заявления хаскеллистов, о том, что у них не бывает "segmentation faults".

Вообще-то, именно не бывает. Unexhaustive pattern - не segmentation fault ни разу. Исключение - если использовать фишки типа unsafePerformIO, но там может быть вообще что угодно.

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

>Знаешь, есть одна штука, которая в гибком состоянии значительно менее полезна, чем в жёстком. Примерно у половины населения земли наличествует.

Радует, что хаскелоиды сами признают, что статика - х***я :)

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

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

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

>Убогенькое.
Нормальное. Свои функции выполняет - т.е. помощь компилятору в оптимизации и проверке в тривиальных случаях.
В нетривиальных, навроде
(with-open-file (in "file-with-class-name") (make-instance (read in)))
оно конечно ничего проверить не сможет, но дак в статике убогой такое вообще невозможно.

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

Какие аннотации мне поставить и где, если я напишу, например, функцию (defun (compose f g) (lambda (x) (f (g x)))) и хочу, чтобы компилятор мне проверял, что тип, возвращаемый g, и тип, принимаемый f на входе, совпадают? Пардон, если наврал в синтаксисе, давно Лисп в руки брал.

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

Большинство лисперов и того не видели.

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

> Радует, что хаскелоиды сами признают, что статика - х***я :)

То есть, разницы между x?%м и x?%нёй ты не видишь?

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

> Для ВСЕХ - не будет. А зачем тебе?

Тут уже требуемое качество языка надо обозвать не демократизмом, а как-то по-другому. Так или иначе, у "языка мечты" (пригодного для построения eDSL) должна быть возможность любой атрибут любой конструкции сделать любым (в т.ч. ON, OFF, ...) *по умолчанию*.

Пример: я допустим хочу тестировать свои функции произвольными наборами входных данных. Для каких-то Алг.Т.Д. может и придется писать свои реализации генератора данных, но для большинства -- можно просто угадать по их структуре. Понятно, что патчить исходники сторонних либ, дописывая везде deriving (MyTest) желания нет.

> Дерайвить можно и отдельно, см. расширение StandaloneDeriving

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

> В Окамле есть отличная система модулей, поэтому типклассы в окамле не очень-то и нужны.

Подозреваю, что тут тоже "потребности в колбасе сегодня нет".

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

чтобы компилятор мне проверял, что тип, возвращаемый g, и тип, принимаемый f на входе, совпадают?

Ты про это?

;; (declaim (ftype (function (fixnum) fixnum) f))                                                                                                                                    
(defun f (x)  (1+ x))                                                                                                                                                             
                                                                                                                                                                                  
(defun g (x)  (write-to-string x))                                                                                                                                                
   

;; declaim (ftype (function (fixnum) string) g))                                                                                                                                                                               
(defun y (x)                                                                                                                                                                      
  (f (g x)))          
; caught WARNING:                                                                                                                                                                 
;   Asserted type FIXNUM conflicts with derived type (VALUES STRING &REST T).                                                                                                     
anonymous
()
Ответ на: комментарий от www_linux_org_ru

> Подозреваю, что тут тоже "потребности в колбасе сегодня нет".

Вокруг классов типов (типоклассов) столько шуму, а какой от них профит? Зачем они вообще нужны то?

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

> Выдаёт, с соответствующим флагом компилера.

А с другим флагом, даже за ошибку считает и не дает скомпилироваться :) Только это не отменяет возможности поулчить такую бяку в ран-тайме.

> Вообще-то, именно не бывает. Unexhaustive pattern - не segmentation fault ни разу.

Да какая разница, как называть - избежать вот таких исключений (segmentation fault, unexhaustive pattern) в ран-тайме - вот ради чего затевалась эта вся песня с тайп-чеками, а что получили в результате - stackoverflow (на сильно ленивых выражениях), unexhaustive pattern (если вдруг забыли перечислить все возможности) и много других "приятных" мелочей, так стоила ли овчинка выделки?

> Исключение - если использовать фишки типа unsafePerformIO, но там может быть вообще что угодно.

Дык про это никто не жалуется. А жалуются, что вроде бы все "чисто", а тут бабах - и "бсод".

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

> Бывает. Некоторые умудряются таки промыть очки.

Расскажи, чем статика значительно лучше динамики. Серьезно, мне действительно очень интересно.

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

Какие аннотации мне поставить и где, если я напишу, например, функцию (defun (compose f g) (lambda (x) (f (g x)))) и хочу, чтобы компилятор мне проверял, что тип, возвращаемый g, и тип, принимаемый f на входе, совпадают?

Подобные вещи можно делать с Qi:

(define compose 
  {(B --> C) --> (A --> B) --> (A --> C)}
  X Y -> (/. Z (X (Y Z))))
anonymous
()
Ответ на: комментарий от anonymous

> Подобные вещи можно делать с Qi:

Перестань насиловать труп. Тем более Qi это совсем не CL.

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

>Подозреваю, что тут тоже "потребности в колбасе сегодня нет".

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

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

> И сколько библиотек лиспа идет с ее поддержкой?

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

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

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

>почему статическая типизация сильно лучше динамической.

Поздравляем! Ваша, заявка на участие в Специальной Олимпиаде принята!

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

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

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

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

Потому что

1. динамическая типизация с полпинка выражается через статическую (при наличии шаблонов/параметрического полиморфизма/по вкусу)

2. но не наоборот

3. статическая типизация позволяет выражать (программисту) предикаты относительно переменных

4. статическая типизация (+вывод типов) позволяет сократить запись по сравнению с динамической

5. через статическую типизацию можно выразить soft typing (а через чистую динамическую -- нет)

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

>1. динамическая типизация с полпинка выражается через статическую (при наличии шаблонов/параметрического полиморфизма/по вкусу)
Это каким образом?
Вырази-ка мне (make-instance (read))
>2. но не наоборот

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

Какие предикаты относительно переменных? Или просто так, умными словами бросаемся?
>4. статическая типизация (+вывод типов) позволяет сократить запись по сравнению с динамической

С дуба рухнул? Каким боком?
Без вывода типов статика только длиннее. С выводом - на примитивных примерах одинаково, на нетривиальных - ух, какие там иногда приходится выстраивать классы типов, лишь бы конпелятор проглотил.
>через статическую типизацию можно выразить soft typing (а через чистую динамическую -- нет)

Гы, сына.
Чтобы на статике построить soft typing тебе надо будет сначала построить интерпретатор языка, имеющего этот самый soft typing. Но так уж получается, что к исходной типизации исходного языка это будет полностью ортогонально.

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

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

>Потому что ...


Поздравляем! Ваша, заявка на участие в Специальной Олимпиаде принята!

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

>1. динамическая типизация с полпинка выражается через статическую (при наличии шаблонов/параметрического полиморфизма/по вкусу)

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

>2. но не наоборот

если есть мп, то почему же нет?

>3. статическая типизация позволяет выражать (программисту) предикаты относительно переменных

может заставляет? А так да, тип integer и будет даже x/0 пропущено.

>4. статическая типизация (+вывод типов) позволяет сократить запись по сравнению с динамической

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

>5. через статическую типизацию можно выразить soft typing (а через чистую динамическую -- нет)

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

Ты так уверенно говоришь, наверное учёный с мировым именем в области CS сюда пожаловал, не?

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

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

Если что-то не компилируется, то никакого ран-тайма не будет, не?

> А жалуются, что вроде бы все "чисто", а тут бабах - и "бсод".

Опять-таки, на unexhaustive pattern невозможно получить BSOD. Программа упадёт с более-менее вменяемым сообщением об ошибке.

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

> Расскажи, чем статика значительно лучше динамики.

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

Ну и от себя можно защититься тоже - никто от временного приступа идиотизма не застрахован.

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

> Это каким образом?

data Term = TFloat Float | TInt Int | TString String | TList [Term] | TPair (Term, Term)

Всё.

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

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

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

> или вывод типов может выводить всё и всегда?

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

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

> Если что-то не компилируется, то никакого ран-тайма не будет, не?

Ну это если мы скормим компилятору определенные флаги, а так - отлично компилируется.

> Опять-таки, на unexhaustive pattern невозможно получить BSOD. Программа упадёт с более-менее вменяемым сообщением об ошибке.

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

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

> data Term = TFloat Float | TInt Int | TString String | TList [Term] | TPair (Term, Term)

Ну да - это "эмуляция" общего типа из динамического типизирования. Только вот незадача Bool тут нет, и не только его кстати, так что определение неполное.

> Ну дык на нетривиальных примерах динамическая типизация просто сдохнет.

Что значит сдохнет?

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

>Ну дык на нетривиальных примерах динамическая типизация просто сдохнет.
С какого хрена?
Динамическая типизация работает _всегда_. Всегда, еще раз.
>data Term = TFloat Float | TInt Int | TString String | TList [Term] | TPair (Term, Term)

Ой да ну, и какая ж это динамическая типизация? Это хрень какая то.
data Term = T
вот это была бы динамическая типизация.

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

Хиндли-милнер весьма убог.
Фишка в том, что некоторые это признают, а некоторые с упорством белорусского трактора отрицают и даже иногда утверждают, что де всесильна.
 
На каких примерах сдохнет динамика - непонятно категорически. Динамика, она компилируется всегда, и, если ошибки типа действительно нету, соответственно, работает.
А вот на каких примерах сдохнет статика, так это, например, на метаобъектном протоколе. Но про такие примеры, и аналоги, адепты извращенного бдсм обычно говорят "не нужно".

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

> Динамическая типизация работает _всегда_.

В том-то и проблема. И если вместо стринга тебе передадут инт - она тоже сработает. И всё навернётся, причём в произвольном месте.

> Ой да ну, и какая ж это динамическая типизация?

Самая натуральная. Тип хранится в самом значении и проверяется в рантайме. Например:

TList arr ! TInt index = arr !! index

TList _ ! _ = error "Не суй всякую хрень вместо индекса!"

_ ! _ = error "И как я тебе должен индексировать неизвестно что?"

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

> если ошибки типа действительно нету, соответственно, работает.

На нетривиальном примере ошибка гарантированно БУДЕТ. Именно потому, что

> она компилируется всегда

Вот потому и сдохнет.

> А вот на каких примерах сдохнет статика, так это, например, на метаобъектном протоколе

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

> обычно говорят "не нужно".

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

Вот, например, Oleg написал для Хаскеля объектную систему, которая практически повторяет синтаксис OCaml-овской, и при этом строго сильнее её. Практически никто не пользуется - потому что в хаскелепрограммах ДЕЙСТВИТЕЛЬНО объекты никому нафиг не нужны. Хотя казалось бы - по первому чиху, как только понадобилось - бери и пользуйся. Компилятор для этого менять не надо (работает со стандартным GHC).

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

> 1. динамическая типизация с полпинка выражается через статическую (при наличии шаблонов/параметрического полиморфизма/по вкусу)

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

Но это вообще говоря - а на самом деле не всякая статическая система типизация может реализовать динамическую. Как простейший пример - гетерогенные списки (это в которых элементом может быть любой тип). Для этого нужен общий тип t - (который обозначает любой другой тип), насколько мне известно только в некоторых модификациях *ml есть специальный dyn тип, а в хаскелле есть Data.Dynamic (правда на мой субъективный взгляд, такая динамическая типизация выглядит совершенно убого), в других языках с менее фичастыми системами типизации этого сделать нельзя, ну разве что только с помощью void* и прочих хаков :). Ну и кроме того, там проблемы с динамическим ad-hoc полиморфизмов по типу clojure.

> 2. но не наоборот

Опять же это, как посмотреть. Точно также как и в статических, в динамических возможен type inference и статическая проверка (посмотри пример на CL, который был выше). Например тот же Qi, чтобы про него там не писали в википедии, является динамическим языком - и там есть возможность рассуждать о _классах значений_, как типах. Т.е. это уже уровень coq, agda и сотоварищей.

> 3. статическая типизация позволяет выражать (программисту) предикаты относительно переменных

Динамическая тоже позволяет. deftype в CL, например. + посмотри динамический Qi.

> 4. статическая типизация (+вывод типов) позволяет сократить запись по сравнению с динамической

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

> 5. через статическую типизацию можно выразить soft typing (а через чистую динамическую -- нет)

И это тоже в молоко - в scheme и erlang есть системы soft typing. А это чистые динамические языки.

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

> вот это была бы динамическая типизация.

Таки это возможно :) Хотя я и не люблю хаскелл, но истина дороже [1]. Хотя это не та динамическая типизация, которую я бы хотел.

[1] http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Dynamic.html

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

> В том-то и проблема. И если вместо стринга тебе передадут инт - она тоже сработает. И всё навернётся, причём в произвольном месте.

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

Как показывает практика (большое количество проектов на динамических языках, которые нормально работают и развиваются) - все не наворачивается в произвольном месте и static typing несколько overrated, хотя конечно весьма полезен.

> _ ! _ = error "И как я тебе должен индексировать неизвестно что?"

А, ну т.е. это ничем не отличается от кидания исключения в динамическом языке в ран-тайме или совершенно не идиоматический для haskell typecase, а смысл тогда? От чего ушли к тому пришли?

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

> Как простейший пример - гетерогенные списки (это в которых элементом может быть любой тип). Для этого нужен общий тип t

См. HList от того же Oleg-а. Гетерогенный список, общего типа не требующий. Вместо этого типы всех элементов участвуют в типе самого списка.

> тот же Qi, чтобы про него там не писали в википедии, является динамическим языком

А можно с этого места подробнее? Я по Qi не спец, так, интересующийся.

> deftype в CL

deftype как раз вводит некую статическую типизацию, если я правильно понимаю.

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

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

Потому что введена - в какой-то мере - статическая типизация.

> Как показывает практика

Моя практика показывает обратное.

> От чего ушли к тому пришли?

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

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

> На нетривиальном примере ошибка гарантированно БУДЕТ. Именно потому, что

На не тривиальном примере в _любом_ случае будет ошибка (и ошибка типа - отнюдь не самая страшная из них).

> Вот, например, Oleg написал для Хаскеля объектную систему, которая практически повторяет синтаксис OCaml-овской, и при этом строго сильнее её.

"Наверное, потому же, почему лисперы не сильно пользуются list comprehension (библиотека incf cl), хотя явно не слабее, чем list-comprehension в хаскеле, и паттерн матчингом (библиотекой cl-unification), хотя она не слабее (haskell)ocaml'овского pattern matching. Наверное, это потому, что pattern matching и list comprehension в лиспопрограммах ДЕЙСТВИТЕЛЬНО никому нафиг не нужен. Хотя казалось бы - по первому чиху, как только понадобилось - бери и пользуйся. Компилятор для этого менять не надо."

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

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

> См. HList от того же Oleg-а. Гетерогенный список, общего типа не требующий. Вместо этого типы всех элементов участвуют в типе самого списка.

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

> А можно с этого места подробнее? Я по Qi не спец, так, интересующийся.

Потому что там 1) типизирование совершенно опционально 2) изначально любая переменная имеет тип T (обощенный тип), если не указано иного. Что Qi сможет вывести, то он и проверет. Причем типы данных там - не алгебраические, а намного более мощные "дедуктивные", т.е. тип у тебя задается предикатом или предикатной функцией (т.е. на самом деле речь идет не типе, а о _классе значений_ - и это принципиальная разница, причем алгебраические типы являются лишь его частным случаем). Причем этот предикат выводится и проверяется (доказывается) во время _статической проверки_ тайп чекером, опять же насколько это вообще возможно. Если _доказано_, что это выражение имеет неправильный тип - выдается ошибка. Т.е. принципиально это более мощная вещь, чем хиндли милнер и ADT.

Тоже самое есть в CL - но там это в сильно обрезанном состоянии и зависит от реализации.

> deftype как раз вводит некую статическую типизацию, если я правильно понимаю.

Нет, как раз deftype пример абсолютно динамической типизации, поскольку он определяет _класс значений_, а не тип.

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

Потому что введена - в какой-то мере - статическая типизация.

Нет, не в какой-то мере. Просто возможен статический анализ динамического языка. Почитай как реализовали систему soft typing для scheme, которая вообще без аннотаций выводит типы и указывает на проблемные места. Можешь еще почитать про то, как это реализовано в erlang'e - правда там _необходимы_ аннотации для типов. Я же говорю - важны инструменты _статической проверки_ кода, а не статическая типизация сама по себе.

Моя практика показывает обратное.

Личная практика не в счет, я точно также могу заявить, что не вижу особой разницы в написании программ в статике или динамики. Но _объективно_ существует множество больших проектов на динамических языках, которые поддерживаются, развиваются и работают _не хуже_ своих «статических» товарищей-конкурентов, поэтому нельзя уверенно говорить, что статическая типизация уменьшает количество багов в ПО или позволяет быстрее и безошибочнее программировать. Просто посмотрите в багтрекер darcs и mercurial, например, беглый взгляд мне выдал ошибку в даркс свзяанную с паттерн-матчингом, а в меркуриал с Unbound local variable. Все - остальные проблемы не _связны_ с типизацией - они логические, и их намного сложнее решить.

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

Определяем функцию факториал.

fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n - 1)

Оно все скомпилировалось. Все окей. Пробуем вычислить.

*Main> fact 5
120
*Main> fact 10
3628800
*Main> fact 16
2004189184

Ну вроде бы похоже на правду.

Теперь то же самое пишем на лиспе

(declaim (ftype (function (fixnum) fixnum) fact))                                                                                                                                 
(defun fact (x)                                                                                                                                                                   
  (if (= x 0)                                                                                                                                                                     
      1                                                                                                                                                                           
      (* x (fact (- x 1)))))

Проверяем (safety 3).

The value 6227020800 is not of type FIXNUM.                                                                                                                                       
   [Condition of type TYPE-ERROR]  

Ясно, не хватает этого типа. Ну что же поменяем тип (или уберем декларацию). Проверяем.

CL-USER> (fact 16)                                                                                                                                                                
20922789888000               

Оба-на, что за фигня, почему результаты разные? Оказывается в нашем любимом выскоко-высокоуровневом хаскелле есть такой «пережиток» прошлого как переполнение разрядной сетки(!), причем это будет справедливо скорее всего для любого статического языка. И в результате придетсся долго искать, где же у тебя ошибка (а она в слишком слабом Int). Пример кстати, взят не из вакуума, а из всеми любимой рассылки haskell-cafe.

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

>1. Это каким образом? Вырази-ка мне (make-instance (read))

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

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

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

Вообще это настолько частый пробел в образовании лисперов, что его надо занести в lisp-lor-faq

>2. В том же лиспе - модифицировать макросами формы, задающие связывание переменных, прикрепить к ним структуры с информацией о типе, и будет полноценная статика.

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

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

>3. Какие предикаты относительно переменных? Или просто так, умными словами бросаемся?

Я -- не бросаюсь. Пример предикатов: массив значений *отсортирован* и значит можно на нем юзать бинарный поиск или (для с++ и выжимания тактов) для данного вектора push_back гарантированно не приведет переаллокации, значит можно юзать оптимизированный вариант, где проверка на переполнение пропущена. (З.Ы. это не стандартная stl)

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

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

> А вот на каких примерах сдохнет статика, так это, например, на метаобъектном протоколе. Но про такие примеры, и аналоги, адепты извращенного бдсм обычно говорят "не нужно".

Нужен. Только в статическом варианте, аналогичном статически-безопасному рефлекшену.

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

>> 4. статическая типизация (+вывод типов) позволяет сократить запись по сравнению с динамической

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

Экономия в библиотеках не очень нужна (и почти даже вредна).

Допустим у нас есть 2 функции в библиотеке

template<class T> int find(T x, Vector<T> v)

template<class T> int find(T x, SortedVector<T> v) // быстрее

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

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

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

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

>> 5. через статическую типизацию можно выразить soft typing (а через чистую динамическую -- нет)

> И это тоже в молоко - в scheme и erlang есть системы soft typing. А это чистые динамические языки.

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

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

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

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

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