Комментарии 25
Xочу в субботу видеть только статьи на тему: «Что лучше: на велосипедах в лес, или на речку?»)
-12
Спасибо за статью, у меня вот только вопрос есть: почему бы не написать просто
Там действительно нужен forall a? Я, честно говоря, уже с год хаскель не трогал, подзабыл нюансы, но мне как-то интуитивно кажется, что этого должно быть достаточно, или я не прав?
data BaconBox = (Tossable a) => BaconBox String a
Там действительно нужен forall a? Я, честно говоря, уже с год хаскель не трогал, подзабыл нюансы, но мне как-то интуитивно кажется, что этого должно быть достаточно, или я не прав?
+1
Опа, разобрался сам, но тогда другой вопрос: мне кажется, или
Как-то не подходит под
BaconBox "bool.and" ["x", "y"] doAnd
Как-то не подходит под
data BaconBox = forall a. (Tossable a) => BaconBox String a
+2
Там мало того, что нужен forall a, но ещё и {-# LANGUAGE ExistentialQuantification #-}, о чём скажет компилятор.
А нужен forall для того, чтобы задать переменную типа, на которую потом можно повесить ограничение класса (Tossable a) и использовать потом в конструкторе. Без этого будет ошибка «Not in scope: type variable `a'».
А нужен forall для того, чтобы задать переменную типа, на которую потом можно повесить ограничение класса (Tossable a) и использовать потом в конструкторе. Без этого будет ошибка «Not in scope: type variable `a'».
+1
О, сколько нам открытий чудных :-P
Одно только не понятно, тип toss:
Но дальше по коду Вы применяете её к двум аргументам, например:
Как такое возможно?
Одно только не понятно, тип toss:
toss :: [String] -> IO String
Но дальше по коду Вы применяете её к двум аргументам, например:
toss [] f = fmap show f
Как такое возможно?
+4
Совершенно верно, должно быть
toss :: [String] -> t -> IO String
, проглядел-с.+3
О, сколько нам открытий чудных :-P
Я тут порылся по хакаджу и обнаружил, что реализация XMLRPC аж от 2003 года (ghc 6.8!) использует подобную технику, только вообще без коробок, а сразу же заворачивая функцию в
[a] -> IO a
.Отсюда вопрос: какого ж хрена остальные продолжают клепать топорные реализации с ручным маршалингом?
0
Скорее всего просто не знают, что так можно. Для многих (да что уж греха таить, и для меня до недавнего времени) функции с переменным количеством аргументов в Haskell вроде printf воспринимаются как чёрная магия и нарушение законов языка. Возможно ситуация бы изменилась, если бы была какая-нибудь библиотека, реализующая эту возможность, или хотя бы популярная статья.
+1
А зачем вообще
Я думал вы придумали, как совместить переменное кол-во аргументов со статическими проверками. Инструменты для этого, кстати, в принципе есть. Делая аргументы просто списком — непонятно как вы защитились от ошибок на рантайме, о которых писали в начале статьи.
BaconBox
после того, как вы ввели тип Tossable
? Почему не [Tossable]
?Я думал вы придумали, как совместить переменное кол-во аргументов со статическими проверками. Инструменты для этого, кстати, в принципе есть. Делая аргументы просто списком — непонятно как вы защитились от ошибок на рантайме, о которых писали в начале статьи.
+2
> А зачем вообще BaconBox после того, как вы ввели тип Tossable? Почему не [Tossable]?
Tossable это не тип, а класс — его нельзя поместить внутрь типа, как нельзя в собаку положить будку.
> Я думал вы придумали, как совместить переменное кол-во аргументов со статическими проверками.
Как вы себе представляете статическую проверку данных из внешнего мира?..
> Делая аргументы просто списком — непонятно как вы защитились от ошибок на рантайме, о которых писали в начале статьи.
Я имел в виду ошибки самих десериализаторов, вызваные копипастой кода и невнимательностью.
Tossable это не тип, а класс — его нельзя поместить внутрь типа, как нельзя в собаку положить будку.
> Я думал вы придумали, как совместить переменное кол-во аргументов со статическими проверками.
Как вы себе представляете статическую проверку данных из внешнего мира?..
> Делая аргументы просто списком — непонятно как вы защитились от ошибок на рантайме, о которых писали в начале статьи.
Я имел в виду ошибки самих десериализаторов, вызваные копипастой кода и невнимательностью.
+2
Да, с Tossable я затупил :)
Статически можно хотя бы проверить количество аргументов. Чтобы программа не компилировалась, если вы передаете функции, которая принимает список из 3 аргументов, список из 2. Например с помощью типа, параметризованного type-level числом.
Статически можно хотя бы проверить количество аргументов. Чтобы программа не компилировалась, если вы передаете функции, которая принимает список из 3 аргументов, список из 2. Например с помощью типа, параметризованного type-level числом.
+1
Мне кажется String в BaconBox лишний.
И конечно спасибо за статью — показана действительно интересная задача решаемая данным подходом.
И конечно спасибо за статью — показана действительно интересная задача решаемая данным подходом.
+1
Можно было конечно сделать контейнером какой-нибудь
Map String BaconBox
или ассоциативный список, но я решил держать метаданные метода вместе. Может пригодится для, например, автоматической генерации документации сервиса. Да и обычно методов не так много, чтобы O(n) (в худшем случае) поиск по списку был настолько прям медленней.+1
Удаление String из BaconBox не помешает держать метаданные с объектом — вы же можете создать тип:
Оно раздельно выглядит композабельней и обобщенней.
Ваш метод идеально решает задачу превращения функции
в функцию
И это я бы рассматривал отдельно от вашей предметной области, и вынес бы этот код в отдельный модуль.
И еще, можно не IO использовать, а просто некую монаду, и тогда изменяя ее, можно будет по разному обрабатывать ошибки, так как будет подставляться разная функция fail.
data MetaData meta obj = MetaData meta obj
Оно раздельно выглядит композабельней и обобщенней.
Ваш метод идеально решает задачу превращения функции
f :: a -> b -> ... -> r
в функцию
f :: [String] -> String
И это я бы рассматривал отдельно от вашей предметной области, и вынес бы этот код в отдельный модуль.
И еще, можно не IO использовать, а просто некую монаду, и тогда изменяя ее, можно будет по разному обрабатывать ошибки, так как будет подставляться разная функция fail.
0
Удаление String из BaconBox не помешает держать метаданные с объектом — вы же можете создать тип:
Я ещё покручу это на реальной задаче и посмотрю как практичней будет.
И это я бы рассматривал отдельно от вашей предметной области, и вынес бы этот код в отдельный модуль.
В идеале, я бы хотел, чтобы оно могло абстрагировать протокол маршалинга и можно было бы строить частные случаи подменяя Read a, Show a, String на другие наборы. Не уверен, что такое вообще возможно, но пока я даже не задумывался о реализации — надо бы сначала частные случаи обкатать в бою.
И еще, можно не IO использовать, а просто некую монаду, и тогда изменяя ее, можно будет по разному обрабатывать ошибки, так как будет подставляться разная функция fail.
Можно и нужно. Просто конкретно в этом посте я сфокусировался на конкретном примере, чтобы можно было объяснить «на пальцах».
А так да, можно сделать
(Monad m, Show a) => m a
и, завернув в Identity, получить диспетчеризацию для чистых функций.0
Но это не совсем то. Но и не совсем не то! awesome.gif
Тут фиксируется класс входных аргументов, гарантирующий [s]успешность[/s] наличие десерилизатора для типа
Картинки не грузятся.
0
Картинки не грузятся.
okay.jpg
[s]успешность[/s]
Эх… А есть чем автоматом перегнать форумную разметку в хабрахтмл?
0
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Священный грааль динамической диспетчеризации