После просмотра руководств GHC и вики Haskell (особенно страницы List instance) , У меня есть лучшее представление о том, как это работает. Вот краткое изложение того, что я узнал:
Проблема
отчет Haskell определяет следующее объявление экземпляра:
Тип (T u1 … uk) должен иметь форму конструктора типа T применяется к переменным простого типа u1, … uk; кроме того, T не должен быть синонимом типа, а все ui должны быть разными.
Части, выделенные жирным шрифтом, — это ограничения, которые меня сбили с толку. На английском языке они:
- Все, что следует за конструктором типа, должно быть переменной типа.
- Вы не можете использовать псевдоним типа (используя ключевое слово
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 ...
Это решение предложил @[Daniel Wagner].
Решение № 3: Ограничения равенства
Наконец, есть еще менее переносимое решение, использующее ограничения равенства:
{-# LANGUAGE TypeFamilies #-}
instance (a ~ Word16) => IsString [a] where ...
Это лучше работает с выводом типа, но с большей вероятностью перекрывается. См. статью Криса Дона на эту тему.
(Кстати, в итоге я создал оболочку foldl'
вокруг Data.Text.Internal и записывает хэш поверх него.)
person
Lambda Fairy
schedule
29.12.2011
[Word16]
, чтобы избежать проблем и конфликтов такого рода. - person ehird   schedule 26.12.2011case s of { Text array offs len -> A.toList array offs len }
не так уж и плохо :) - person ehird   schedule 27.12.2011newtype
в списке. - person ehird   schedule 27.12.2011