Почему я не могу определить экземпляр Haskell Arrow в терминах arr и ***/&&&

Я все еще разбираюсь в определении и использовании Arrows в Haskell. Определяя новые стрелки, мне гораздо легче думать в терминах *** или && & а не первый и второй, так как большую часть времени я хочу специальную обработку, когда сочетаются две стрелки.

Однако класс Arrow не позволяет определять стрелку в терминах arr и *** или && &, и требует определения первого для включения. Это означает, что я вынужден писать код следующим образом:

instance Arrow X where
  arr f = ...
  f (***) g = ...
  first f = f *** arr id

Мне кажется, что не было бы никакого вреда в том, чтобы включить определение по умолчанию "first", а также в модуль Control.Arrow. Это позволило бы нам выбирать между определением либо первого, либо ***.

Есть ли веская причина, почему первое определение по умолчанию не было включено в класс Arrow? Единственная причина, по которой я могу думать, это то, что пользователь может оставить определение first и *** и то, и тогда у вас будут круговые определения, но это единственная причина?

Ответ 1

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

Ответ 2

Data.Monoid имеет аналогичное отсутствующее альтернативное минимальное полное определение: mconcat. Как и Arrow, эта альтернатива отсутствует из соображений производительности. mappend a b = mconcat[a,b] неэффективен из-за соответствия шаблонов в mconcat.

С помощью стрелок неэффективность менее очевидна, но более жестока: подумайте о невозможности оптимизировать arr id прочь:

Используя CleisliArrow в качестве примера Arrow, это примерно так:

first f (x,y) = do
    x' <- f x
    return (x',y)

И это будет:

first f (x,y) = do
    x' <- f x
    y' <- arr id y
    return (x',y')

Функция arr не может сопоставлять шаблону с функцией id и поэтому должна вводить дополнительные служебные данные для обертывания этой функции.