Создание новых типов в таких случаях плодит лишние сущности, иногда подобные типы «выламываются» из общей системы, которую приходится под них адаптировать. А если еще добавить к этому, что это расширение библиотеки, которая не тобой писана… Увы, на частном примере это не очень хорошо заметно, поэтому и кажется, что проблема искусственная. В реальной ситуации, когда в системе десятки типов, это становится заметно, но как впихнуть такой пример в формат статьи, я пока не очень понимаю. Постараюсь все же развернуть тему чуть позднее.
Да, именованные экземпляры были бы неплохим решением. Интересно, что мешает их реализовать? Еще одну возможность я вижу в том, чтобы предоставить возможность перекрытия экземпляров в пределах модуля. В случае паранойи можно было бы предусмотреть расширение, которое отключающает проверку перекрытия экземпляров в некоторых случаях. А то получается, как в известной присказке — «Хаскель не даст вам прострелить свою ногу» :-).
Насчет «нужных в данный момент». Слишком часто такие определения многократно повторяются. Иначе не возникало бы желание обобщить их. Но не больше, чем это необходимо :-).
Двупараметрический тип попытались использовать как однопараметрический, редуцировав совершенно произвольно первый по порядку параметр. Или математика запрещает рассматривать другие случаи, когда нужно редуцировать, скажем, последний параметр, а остаток рассматривать как функтор?
Впрочем, в аппендиксе я все развернул. Я всего лишь против того, чтобы частное решение выносилось на уровень системы, тем более, в условиях, когда последствия такого решения невозможно заблокировать. Математика тут ни при чем.
Вообще, не очень удачно разделены группы. Поведение 2, 3, 4, 6, как правило, вызваны одной и той же чертой характера, поэтому почти всегда проявляются одновременно. То же самое можно сказать про пару 5, 7. Только первый и последний пункты стоят особняком.
Увы, скорее вынужден отнести себя к первой группе.
Спасибо! Честно говоря, просто замылился глаз, когда писал код, а компилятор не дал вменяемого сообщения — предложил заняться выводом типа, а не проверить вызов.
Приятно также, что увеличение сразу трех элементов теперь также работает. То есть, как минимум одну свою проблему я все-таки решил :-).
наверняка требуют RankNTypes расширения. Включите его.
Интересно, почему мне об этом ничего не сказал компилятор?
Самым простым, будет создать функцию
Увы, решение с отдельной функцией не подходит. Мне нужно либо вообще исключить кортежи из класса функторов, либо обеспечить единую обработку, но с нужным мне поведением.
Скажем так, если я заведу отдельную функцию both, то мне придется придумать, как реализовать вызов вида
both inc [1, 2, 3, 4, 5]
То, что вы пытаетесь определить как Функтор2 почти наверняка является БиФунктором.
Да, это классно. Теперь попробую еще поискать трифункторы. В другом комментарии я отметил, что это проблема семантического поиска. Я понимаю, что мне нужно, но не могу сказать, как именно это называется. Так что, hoogle не всегда рулит :-).
Разумно, но в общем контексте не пойдет. В оригинальном проекте мне нужно, чтобы изменилось поведение именно для кортежей, которые используются в коде, который мне недоступен. В следующей статье я собираюсь объяснить этот момент.
Честно говоря, Incable — только для демонстрации. В оригинале был класс Reducable, но думаю, это вряд-ли кому-то тут что-то скажет. Скажу честно, использовать для демонстрации Enum просто не догадался. Не в том суть, а подобные мелочи можно шлифовать бесконечно.
Не, ну понятно, что путем частичного вычисления любой тип можно свести к однопараметрическому. Интереснее, когда функтор воздействует на все свои части. Вот, оказалось, что я заново открыл бифункторы. Знать бы еще сразу, что они так называются. Но в мне также интересны трифункторы. Я ведь задачу поставил в более общем виде.
Вполне возможно, что я неправильно понимаю некоторые вещи, но чтобы грамотно их изложить, в чем именно мое непонимание, приходится очень много объяснять. Поверьте, то, чем я поделился — только небольшой кусок проблем, с которыми я столкнулся. Мне просто удалось выделить этот кусок в чистом виде.
Нет, конечно же. Проблема неточности в вычислении глубже, это можно проверить с помощью аналогичного примера на C. Просто в Haskell есть возможность красиво обойти эту проблему. Ну и то, что QuickCheck позволяет найти совершенно неожиданные ситуации, когда что-то работает не так, как ожидалось. Например, (abs s) в инварианте тоже ведь вначале не было.
Я просто не хотел утяжелять статью ненужными, на мой взгляд, деталями. В оригинале инвариант выглядел так:
prop_mul_distance s p1 p2 =
distance (s *. p1) (s *. p2) == (abs s) * (distance p1 p2)
Здесь масштабируется не длина вектора, а положение двух точек на плоскости. Функция distance вычисляет расстояние между этими точками, а оператор (*.) умножения на целочисленный скаляр представляет масштабирование координат.
Вот при проверке этого инварианта QuickCheck и обнаружил нарушение. И как теперь, не вскрывая «черного ящика», обеспечить необходимую проверку?
Сорри за сырой ответ это архив ньюсгруппы relcom.rec.puzzles, где мы играли в решение этой задачи. К сожалению, потерял архив с исходниками там еще было решение на ассемблере x86. Может, еще найду...
"Язык-шутка HQ9+ состоит из всего четырех инструкций: H выводит «Hello, world!», Q печатает текст самой программы, 9 – 99-бутылочный тест, а + – увеличивает значение внутренней переменной (без всякого умысла – прочитать это значение все равно нельзя)."
Вот можно и взять эти три задачи за основу :-). Я в свое время пытался писать интроспекцию для разных языков, могу поделиться.
Да, именованные экземпляры были бы неплохим решением. Интересно, что мешает их реализовать? Еще одну возможность я вижу в том, чтобы предоставить возможность перекрытия экземпляров в пределах модуля. В случае паранойи можно было бы предусмотреть расширение, которое отключающает проверку перекрытия экземпляров в некоторых случаях. А то получается, как в известной присказке — «Хаскель не даст вам прострелить свою ногу» :-).
Насчет «нужных в данный момент». Слишком часто такие определения многократно повторяются. Иначе не возникало бы желание обобщить их. Но не больше, чем это необходимо :-).
Впрочем, в аппендиксе я все развернул. Я всего лишь против того, чтобы частное решение выносилось на уровень системы, тем более, в условиях, когда последствия такого решения невозможно заблокировать. Математика тут ни при чем.
Вообще, не очень удачно разделены группы. Поведение 2, 3, 4, 6, как правило, вызваны одной и той же чертой характера, поэтому почти всегда проявляются одновременно. То же самое можно сказать про пару 5, 7. Только первый и последний пункты стоят особняком.
Увы, скорее вынужден отнести себя к первой группе.
Приятно также, что увеличение сразу трех элементов теперь также работает. То есть, как минимум одну свою проблему я все-таки решил :-).
Интересно, почему мне об этом ничего не сказал компилятор?
Увы, решение с отдельной функцией не подходит. Мне нужно либо вообще исключить кортежи из класса функторов, либо обеспечить единую обработку, но с нужным мне поведением.
Скажем так, если я заведу отдельную функцию
both
, то мне придется придумать, как реализовать вызов видаДа, это классно. Теперь попробую еще поискать трифункторы. В другом комментарии я отметил, что это проблема семантического поиска. Я понимаю, что мне нужно, но не могу сказать, как именно это называется. Так что, hoogle не всегда рулит :-).
Вполне возможно, что я неправильно понимаю некоторые вещи, но чтобы грамотно их изложить, в чем именно мое непонимание, приходится очень много объяснять. Поверьте, то, чем я поделился — только небольшой кусок проблем, с которыми я столкнулся. Мне просто удалось выделить этот кусок в чистом виде.
Здесь масштабируется не длина вектора, а положение двух точек на плоскости. Функция distance вычисляет расстояние между этими точками, а оператор (*.) умножения на целочисленный скаляр представляет масштабирование координат.
Вот при проверке этого инварианта QuickCheck и обнаружил нарушение. И как теперь, не вскрывая «черного ящика», обеспечить необходимую проверку?
Сорри за сырой ответ это архив ньюсгруппы relcom.rec.puzzles, где мы играли в решение этой задачи. К сожалению, потерял архив с исходниками там еще было решение на ассемблере x86. Может, еще найду...
Вот можно и взять эти три задачи за основу :-). Я в свое время пытался писать интроспекцию для разных языков, могу поделиться.