Почему 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
- наверное, не стоит заморачиваться.