- 1
f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex), Handler (\ (ex :: IOException) -> handleIO ex)]
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+128
f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex), Handler (\ (ex :: IOException) -> handleIO ex)]
Собственно это пример как в хаскеле перехватывать исключения из одного выражения expr.
Выглядит конечно отстойно. Очень многословно и судя по всему метода проще нет. И понятное дело, в чистых ленивых функциях это не работает. Ловить исключения можно только в грязных IO-функциях, тк сигнатура такова: catches :: IO a -> [Handler a] -> IO a
HaskellGovno 21.10.2012 19:15 # +2
1)Почему всё так отстойно?
2)Как в божественном Хаскеле список [] умудряется хранить сигнатуры разных типов функций?
В данном случае мы видим, что первая лямбда имеет тип приблизительно :: ArithException -> IO () . А вторая лямбда имеет тип приблизительно :: IOException -> IO () .
Как такое возможно? Допустим, что они привились к некоторому базовму типу, типа :: Object -> IO () (понятно, что это врятли так, но всеже допустим.). Привидение к некоторому мифическому абстрактному Object всё же необходимо, иначе просто разные сигнатуры (лямбды разных типов) не загонишь в один список. В данном случае что-то типа [Handler (Object -> IO ())] получилось. Разные типы можно было бы в кортеж загнать, но здесь список и он должен содержать элементы одного типа. Раз всё привелось к одному типу, то тогда статическая информация о типе ловимого исключения должна теряться. Но она не теряется. Почему? Как? То есть собственно вопросы:
1.1)Почему скомпилировался список из разнотипных элементов? 1.2)Почему не потерялась статическая информация о типе исключения?
bormand 21.10.2012 20:02 # +2
Вот видимо через этот Typeable он и выбирает подходящий элемент из списка. Лень сегодня копаться глубже, сорри ;(
HaskellGovno 21.10.2012 20:16 # +2
Но моя догадка, что сигнатура лямбды приводится к общему типу, верна?
Просто после такого приведения, мне не понятно, как вообще достать тип параметра сигнатуры. Тоесть как вытащить из экземпляра лямбдочки :: Object -> IO () конкретно "кусок" сигнатуры, тот что типа Object, чтобы потом из него получить уже с помощью Typeable реальный тип исключения.
И ещё не понятно зачем нужен этот самый Handler обернутый вокруг лямбдочки, который только удлиняет запись для перехвата каждого исключения.
bormand 21.10.2012 20:21 # +2
По идее, нельзя сделать произвольные функции инстансом тайпкласса. Поэтому вводится промежуточная сущность - Handler, которая как раз принадлежит нужному тайпклассу, благодаря чему ее можно засунуть в список. И, видимо, у этого handler'а должен быть метод, которым он сможет обработать экцепшн, если он ему понравится (совпадут тайпиды). Как-то так.
bormand 21.10.2012 20:28 # +2
catchesHandler) - она перебирает обработчики в цикле, пытаясь вызвать fromException, и если это удается - вызвать сам обработчик.
P.S. Не совсем въезжаю откуда берется тип.
HaskellGovno 21.10.2012 20:51 # +2
>forall e . Exception e => Handler (e -> IO a)
Про forall прочитать ещё не успел. Сейчас буду вчитываться. Но почему такая странная форма записи? Обычно вроде вместо точки используется запятая при этом тайпклассы начинаются с большой буквы и все это берется в скобочки или как-то так, например:
(Forall e , Exception e) => Handler (e -> IO a)
>(throw e)
Кидает исключение или возвращает в качестве результата функции throw?
Хаскел - это как черная дыра. И интересно и затягивает.
Вот так каждый раз. как что-то интересное увидел - хочется заглянуть как они это реализовали...
bormand 21.10.2012 20:55 # +2
>Кидает исключение или возвращает в качестве результата функции throw?
Ну судя по тому, что оно вызовется когда foldr переберет все варианты - это просто перевброс необработанного исключения.
forall это не класс, это специальная форма записи. Читается вроде-бы так: "Для каждого типа e, такого, что e является Exception". (Математический квантор всеобщности).
HaskellGovno 21.10.2012 21:08 # +2
>Throw an exception. Exceptions may be thrown from purely functional code, but may only be caught within the IO monad.
Не очень понимаю. Функция вброса исключения не IO. При этом она возвращет некую а. При этом результат вброса исключения сложили в аккумулятор foldr и ниже функцией tryHandler приняли в res. Я так понимаю тут в ленивом коде исключения имеют особое значение и ни приводят к никакой размотки стека, а это обычное значение, хранящееся на месте результата функции или в константе произвольного типа. Притом, если их не "трогать", то и исключения не произойдет. Точнее исключение будет просто лениво храниться например в некоторой константе или в списке и приложение совсем не упадет, пока его не "потрогаешь".
bormand 21.10.2012 21:15 # +2
Она имеет произвольный возвращаемый тип. Т.к. на самом деле возврата из нее нет, то и на тип всем пофиг.
> пока его не "потрогаешь"
Ну да, (throw e) спокойно лежит невыполненным дожидаясь своего часа. Если во время исполнения foldr не найдется подходящиго хендлера - это исключение заденут, и оно будет вброшено, и возможно поймано на более высоких уровнях.
P.S. Я вот не пойму, как определяется тип для fromException. Тип handler'а ведь безвозвратно проёбан.
HaskellGovno 21.10.2012 21:45 # +2
>fromException :: SomeException -> Maybe e
>fromException ex =
Я вот тоже совсем не понимаю. Во первых почему он возвращает Maybe e, а не e. Видимо потому, что тип исключения ex и e если не совпали, то он возвращает Nothing, иначе Just e. При этом тип исключения результата функции fromException, а именно e он берет за счет вывода типа из использования результата этой функции, так как дальше результат передаётся в лямбду, принимающую параметр определенного типа.
Например если лямбда handler принимает ArithException, то вывод типа выводит тип результата функции fromException как MayBe ArithException.
(Извиняюсь, если говорю очевидные вещи. Я уверен, что вы это знаете лучше меня. Просто пытался рассуждать логически.)
Но есть одно но:
handler имеет тип Object -> IO () и принимает в качестве параметра некий тип Object (условно говоря). Переход к Object был необходим, чтобы покласть в одну коллекцию все разнотипные лямбды. То есть на самом деле выводиться все тот же тип MayBe Object в качестве результата fromException. То есть тип действительно теряется и я тоже не понимаю как он работает, тк fromException (ex::SomeException) c результатом MayBe Object должен вернуть всегда Nothing , тк тип ex с Object не совпал... :(
Object я говорил для простоты. На самом деле он имеет тип (Exception e => e).
bormand 21.10.2012 21:58 # +2
Здесь я попытался повторить ту же самую модель - тип SomeTest, в который при помощи toTest можно поместить любой инстанс класса Test. И функцию test, которая прогоняет массив обработчиков над неким SomeTest и возвращает результат подходящего обработчика, или Nothing.
P.S. Да, оно работает. Да, я не понимаю почему оно работает. Или в строчке (Handler handler) оно видит точный тип хендлера, или я ничего не понимаю.
HaskellGovno 21.10.2012 23:12 # +1
HaskellGovno 21.10.2012 22:04 # +2
Действительно тип теряется и превращается в
fromException :: SomeException -> MayBe Object
а если говорить правильнее, то
fromException :: Exception e => SomeException -> MayBe e
Но мы помним, что Exception потомок Typeable
Это значит, что он реализует метод fromException как-то так:
fromException ex = (typeid ex) == (typeid $ throw e)
Понятно, что в хаскеле typeid имеет другое название, но у Typeable подобная функция есть.
Если что-то не понятно, то могу пояснить подробнее.
HaskellGovno 21.10.2012 22:10 # +2
fromException :: SomeException -> MayBe Object из-за вывода типа.
bormand 21.10.2012 22:11 # +2
Я вот не пойму другой момент - как хаскель угадывает нужный тип в tryHandler, ведь там обезличенный handler и обезличенный t. Вот если я пойму, как выводится тип в данном случае - я пойму принцип работы этого механизма.
HaskellGovno 21.10.2012 22:52 # +2
А что тут думать? Теперь это более или менее очевидно:
tryHandler :: (Exception e) => (Handler (e -> IO ())) -> e -> IO ()
>Но чтобы fromException корректно работал, нам нужно знать тип его возвращаемого значения.
Я же выше описал. Тип результата fromException выводится выводом типа из использования этого самого результата и получает тип (Exception e) => SomeException -> MayBe e
То есть результат fromException имеет тип (Exception e) => Maybe e, что есть аналог интерфейса из прочих языков, завернутого в контейнер MayBe.
То есть результат fromException - экземпляр класса на псевдокоде:
Exception в свою очередь потомок Typeable и Show, то есть потомок ITypeable и IShow. А это значит, что у IException как у потомка ITypeable есть аналог метода typeid и поэтому можно сравнить выведенный тип результата с типом проверяемого исключения.
А выводится тип результата fromException из использования, тк мы передаём этот результат в функцию handler, имеющую тип (Exception e) => e -> IO ().
То есть получается такая ситуация, из которой легко вывести тип результата:
handler(ИзвлечьИзMaybe(fromException(ex) )); То есть в данном случае handler принимает IException, а оттуда можно вверх по цепочке применений легко вывести, что fromException вернет MayBe IException.
Я пытался провести аналогии между интерфейсами IException и классами типами примененными к некоторому абстрактному типу e: (Exception e => e). Я почти уверен, что примерно так оно и реализовано в Хаскелл.
А вообще что-то вы в меня закрали сомнения... Пойду смотреть вашу программу...
bormand 22.10.2012 05:30 # 0
HaskellGovno 21.10.2012 23:04 # +2
Я кстати ошибку грубую выше допустил. На псевдокоде должно быть примерно так:
fromException ex = if ((typeid ex) == (typeid $ throw e)) (just ex) else nothing
Я смотрю, вы какой-то cast применяете, вместо этого в своём коде, но видимо он примерно так же и реализован где-то внутри. Сейчас буду смотреть подробне.
bormand 22.10.2012 05:22 # +1
HaskellGovno 21.10.2012 21:17 # +2
data Either a b = Left a | Right b
а что-то типа:
data (forall e) => Either a b = Left a | Right b | ВнутреннийТипОберткаИсключений e
Так и с прочими стандартными типами типа Char и прочих.
Извиняюсь за возможно не верное обращение с forall
bormand 21.10.2012 21:22 # +2
bormand 21.10.2012 20:08 # +3
Вот Вам на почитать перед сном: http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types.
P.S. Запихать не проблема, сложнее вынуть. Элементы гетерогенного списка "обезличиваются", к ним можно обращаться только через методы классов, перечисленных в forall. Поэтому если не пристегнуть какой-нибудь Typeable - вынуть их оттуда в исходном виде уже не удастся. Как видим в данный список можно поместить все, что принадлежит тайпклассу Show.
HaskellGovno 21.10.2012 22:22 # 0
То есть на C#-подобном псевдокоде: Теперь можно обратиться как к c.obj.Dispose() так и к c.obj.GetObjectData().
wvxvw 21.10.2012 19:28 # +6
Хаскел - не язык для написания програм, а язык для того, чтобы потешить эго математиков-прерафаэлитов, способных мыслить только заученными цитатами классиков 14-15 веков.
HaskellGovno 21.10.2012 19:52 # +3
Ну и зачем я его тогда изучаю? Не должно быть такого. Все языки программирования пишут для написания программ. Хаскелл должен для этого подходить. Не разрушайте мою детскую влажную мечту. Хаскелл божественен. Он есть царь-бог всех языков и на Земле и на Небе. :/
roman-kashitsyn 21.10.2012 23:19 # +3
roman-kashitsyn 22.10.2012 00:22 # +3
К слову, теория множеств возникла в 19 веке. А теория категорий - изобретение математиков 20 века. В том, что исключения в Haskell выглядят хреново, чести не много, однако же, Maybe и Either удовлетворяют большую часть потребностей и весьма удобны. Исключения основном нужны при работе с файлами и базами данных, да и тут всё не так уж плохо: обработка исключения в Haskell, с моей точки зрения, выглядит проще и понятнее, чем работа с (более мощным и илитным) сигнальным протоколом CL.
wvxvw 22.10.2012 01:32 # +4
Я не знаю... я каждый раз как вижу код какого-нибудь мудака с кучей степеней (по математике), который пишет (1 / Х) * У потому, что он привык так на бумажке писать. И мало того, еще и считает, что человек реализующий язык должен учитывать такие дибильные случаи и специально закладывать возможность трансформации таких выражений в нормальные. Хочется такого рожей об клавиатуру.
Я могу понять, когда человек не знакомый вообще с концепцией, или просто неопытный так сделает. Но когда человек умышленно делает через жопу, когда он уже наверняка может понять, что его бюрократическое следование бумажке - вредит, и тем не менее с высокой кафедры продолжает вещать такую херню...
Нет ни одного достаточно существенного повода для того, чтобы не использовать разрушающие присваивания. Более того, это основа основ в хорошем программировании. Нет вообще никаких мыслимых и немыслимых недостатков от побочных еффектов - все что об этом написано и подписано "умами" совеременности - бред сивого мерина, ничем абсолютно не подкрепленный. Больше всего это напоминает рассуждения схоластов о законах физики, категорически отрицавших любой эмпирический опыт (т.е. только основываясь на изучении святого писания).
В программировании есть совершенно конкретные реалии и конкретные задачи. Человек, который умышленно избегает решений эксплуатирующих возможности и ресурсы - не просто дурак, а злостный идиот, который своим примером еще и других смущает.
bormand 22.10.2012 05:24 # +2
Си быстро опускает любящих так писать с небес на землю... Мой первый график 1/2*sin(x) на С выглядел как прямая именно по этой причине.
Lure Of Chaos 22.10.2012 11:43 # 0
если ее вообще было заметно, т.к. лежала на оси
bormand 22.10.2012 12:21 # 0
HaskellGovno 22.10.2012 20:33 # +2
О Хаскел всемогущий на небесах! да святится имя Твое
да приидет Царствие Твое
да будет воля Твоя и на земле, как на небе
хлеб наш насущный дай нам на сей день
и не введи нас в искушение (использовать мутабильные переменные), но избавь нас от лукавого (императивных парадигм). Ибо Твое есть Царство и сила и слава во веки. Аминь.
PS: Все точки с запятой в конце строк убрал.
Lure Of Chaos 26.10.2012 02:33 # 0
roman-kashitsyn 22.10.2012 12:19 # +3
Возьмём, к примеру, Эйлера. Он был не только блестящим и невероятно плодовитым математиком, породившим множество методов и даже новых разделов (!) математики, он был прекрасным инженером, глубоким практиком. У него огромное количество работ, посвящённых практическому применению дифференциального и вариационного исчисления.
Уравнения Лапласа для производных комплексных функций были получены в процессе исследований гидродинамики.
Гауссу принадлежат несколько изобретений, включая электрический телеграф. Он провёл довольно много опытов вместе с Вебером, и помог ему построить математическую модель электромагнитизма.
Практически все математики вплоть до 20 века были по совместительству физиками и инженерами. Потом уже выделилась каста "пуристов", занимающихся "диким матаном", который чуть позже нашёл себе применение в современных физических теориях. Да и среди них довольно часто встречаются практики.
wvxvw 22.10.2012 13:03 # +1
:)
Я горовю исключительно про математиков-прерафаелитов (прерафаелиты, это относительно современное явление, это такие готы конца 19, начала 20-го века).
Это люди, которые, когда реализуют функции в программировании, вместо того, чтобы написать if, который им в их формулах тяжело дается, делают примерно следующее:
где y может принимать значения только 0 и 1. (Но это хорошо, если именно так запишут, и можно будет легко отловить, а как правило, закопают так, что хрен найдешь). Ну и, естесственно, без ленивых вычислений с таким очень тяжело бороться. Но это люди, которые как правило сами себе создают неразрешимые пробемы и потом мужественно их решают.
Это не недостаток математики, ни в коем случае. Это в моем представлении, недостаток системы образования, и, как результат, глубоко искаженного представления о действительности.
defecate-plusplus 22.10.2012 13:05 # 0
wvxvw 22.10.2012 13:15 # 0
defecate-plusplus 22.10.2012 13:21 # +3
а не овер9000 пейдждаунов унылого комик-санса - не осилил и 10%
3.14159265 22.10.2012 14:09 # 0
Заебали форсить Теслу - посмотрите серию симпосонов ниже.
wvxvw 22.10.2012 14:19 # 0
3.14159265 22.10.2012 14:33 # +1
Это очень смелое заявление.
wvxvw 22.10.2012 15:28 # +2
3.14159265 22.10.2012 13:46 # 0
Season 10 Episode 2: The Wizard of Evergreen Terrace.