Снятие общей трубы трубопровода Хаскелла - PullRequest
6 голосов
/ 16 декабря 2011

У меня есть довольно распространенный шаблон Хаскелла, который появляется во многих местах.Это выглядит примерно так (при создании экземпляров классов):

a <= b = (modify a) <= (modify b)

примерно так (с обычными функциями):

fn x y z = fn (foo x) (foo y) (foo z)

и иногда даже с кортежами, как в:

mod (x, y) = (alt x, alt y)

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

Ответы [ 2 ]

12 голосов
/ 16 декабря 2011

Для случая (<=) рассмотрите определение compare вместо этого;затем вы можете использовать Data.Ord.comparing , например, так:

instance Ord Foo where
  compare = comparing modify

Обратите внимание, что comparing можно просто определить как comparing f = compare `on` f, используя Data.Function.на .

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

Для mod:

mod = alt *** alt

с использованием Control.Arrow. (***) - читать a b c как b -> c в сигнатуре типа;стрелки - это просто общая абстракция (например, функторы или монады), экземпляром которых являются функции.Вы можете определить both = join (***) (что само по себе является сокращением для both f = f *** f);Я знаю по крайней мере еще одного человека, который использует этот псевдоним, и я думаю, что он должен быть в Control.Arrow.

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

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

Так, например, для вашего mod случая вы можете абстрагироваться от alt, получая \f (a,b) -> (f a, f b), а затем искать его тип, (a -> b) -> (a, a) -> (b, b) - есть точное совпадение, но оно находится в библиотеке графов fgl, от которой вы не хотите зависеть.Тем не менее, вы можете видеть, как возможность поиска по типу может быть очень полезной!

Существует также версия Hoogle для командной строки с интеграцией GHCi;см. на странице HaskellWiki для получения дополнительной информации.

(есть также Hayoo , который просматривает весь Hackage , но немного менее умный стипы; какой вы используете, зависит от личных предпочтений.)

4 голосов
/ 16 декабря 2011

Для некоторых шаблонов Data.Function.on может быть полезным, хотя в этих примерах он не набирает много

instance Ord Foo where
    (<=) = (<=) `on` modify   -- maybe

mod = uncurry ((,) `on` alt)  -- Not really
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...