После просмотра руководств GHC и вики-страницы Haskell (особенно страницы List instance ) у меня появилось лучшее представление о том, как это работает.Вот краткое изложение того, что я выучил:
Проблема
Отчет Haskell определяет объявление экземпляра следующим образом:
Тип( T u 1 … u k ) должен принимать форму конструктор типа T , применяемый к переменным простого типа u 1 ,… u k ;кроме того, T не должен быть синонимом типа , а все u i должны быть различны.
Части, выделенные жирным шрифтом, представляют собой ограничения, которые сработалименя.На английском языке это:
- Все, что находится после конструктора типа , должно быть переменной типа.
- Нельзя использовать псевдоним типа (используя
type
ключевое слово), чтобы обойти правило 1.
Так как это связано с моей проблемой?
[Word16]
- это просто еще один способ написания [] Word16
.Другими словами, []
является конструктором, а Word16
является его аргументом.
Поэтому, если мы попытаемся написать:
instance IsString [Word16]
, что совпадает с
instance IsString ([] Word16) where ...
он не будет работать, потому что он нарушает правило 1, как любезно указывает компилятор.
Попытка скрыть его в синониме типа с
type String16 = [Word16]
instance IsString String16 where ...
не будетработать либо, потому что это нарушает часть 2.
Таким образом, в существующем состоянии невозможно [Word16]
(или список из что-нибудь , если на то пошло) реализовать IsString
в стандартном Haskell.
Введите ... (барабанная дробь, пожалуйста)
Решение № 1: newtype
Решение, которое @ehird предлагает заключить в newtype
:
newtype String16 = String16 { unString16 :: [Word16] }
instance IsString String16 where ...
Обходит ограничения, потому что String16
больше не псевдоним, это новый тип (извините за каламбур)!Единственным недостатком этого является то, что мы должны затем обернуть и развернуть его вручную, что раздражает.
Решение # 2: Гибкие экземпляры
За счет переносимости мы можем полностью снять ограничениес гибкими примерами:
{-# LANGUAGE FlexibleInstances #-}
instance IsString [Word16] where ...
Это было решение, предложенное [Даниэлем Вагнером].
(Кстати, в итоге я сделал foldl'
обертку вокруг Data.Text.Internal и запись хеша поверх него.)