Почему IsList требует toList?

Когда используешь -XOverloadedStrings вы можете реализовать, для чего требуется только функция fromString. Теперь, если вы хотите использовать строковые литералы для сопоставления с образцом, вам также необходимо реализовать, что имеет смысл:

      f :: MyString -> Bool
f "foo" = True
f _ = False

-- equivalent to
f x
  | x == fromString "foo" = True
  | otherwise             = False

Но тогда почему IsList класс типа, который используется с -XOverloadedListsтребовать, чтобы вы реализовали? В вики единственный упомянутый вариант использования - это сопоставление с образцом. И я понимаю, что этого недостаточно для сопоставления с образцом списка. Но потом toListдолжен быть в другом классе типа, который требуется только в том случае, если вы хотите использовать сопоставление шаблонов списка с вашим типом, как и IsStringне требует Eq.

Меня раздражает то, что состояние fromList . toList = id должно быть выполнено, но это просто не может быть гарантировано для некоторых типов, таких как, например, неупорядоченная коллекция, которая не дает никаких гарантий, что порядок элементов сохраняется.

Это кажется очень непоследовательным.

1 ответ

По сути, потому что вы хотите связать переменные в шаблоне вроде

      f :: MyList Int -> Bool
f [x, y] = x > y

... в то время как строковые литералы, которые вы используете при определении:

       f :: MyString -> Bool

... никогда не будет связывать переменную (Haskell не выполняет интерполяцию переменных, например let x = "an interpolation" in "string with {x} inside"

Чтобы увидеть, как это работает, предположим, что совпадения шаблонов будут переведены точно так же, как -XOverloadedStrings. Соответствие шаблону

      f [x,y] = x > y

будет переведено как

      f z
 | z == fromList [x, y] = x > y

Но fromList [x, y] не является шаблоном конструктора : для данного z, может быть несколько разных значений для x и y такой, что fromList [x, y] == z (В вашем примере неупорядоченная коллекция {1, 2} равно fromList [1, 2] но также fromList [2, 1] - так должен результат f {1, 2} быть True или же False?

Вот почему он нужен, а перевод вместо этого

      f z
 | toList z == [x, y] = x > y

Или с шаблоном просмотра :

      f (toList -> [x,y]) = x > y

Итак, в конечном итоге, ваш IsList класс без toList не допускал бы перегруженных шаблонов списков, но все же позволял бы обозначать вашу неупорядоченную коллекцию {1,2} используя нотацию списка [1,2]. Но тогда у нас было бы -XOverloadedLists и -XOverloadedListPatterns - наверное, не стоит заморачиваться.

Другие вопросы по тегам