Lam*_*iry 29 haskell typeclass
我正在编写一个使用UTF-16字符串的应用程序,并且为了利用重载的字符串扩展,我试图IsString为它创建一个实例:
import Data.Word ( Word16 )
import Data.String ( IsString(fromString) )
type String16 = [Word16]
instance IsString [Word16] where
fromString = encodeUTF16
encodeUTF16 :: String -> String16
Run Code Online (Sandbox Code Playgroud)
问题是,当我尝试编译模块时,GHC 7.0.3抱怨:
Data/String16.hs:35:10:
Illegal instance declaration for `IsString [Word16]'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `IsString [Word16]'
Run Code Online (Sandbox Code Playgroud)
如果我注释掉实例声明,它会成功编译.
为什么拒绝这个?该实例[Char]看起来很像同样的事情,但它编译罚款.有没有我错过的东西?
Lam*_*iry 80
在浏览了GHC手册和Haskell wiki(特别是List实例页面)之后,我对它的工作原理有了更好的了解.以下是我学到的内容摘要:
该哈斯克尔报告定义了一个实例声明是这样的:
类型(T u 1 ... u k)必须采用应用于简单类型变量u 1,... u k的类型构造函数T的形式; 此外,T不能是类型的同义词,而且我必须都是不同的.
以粗体突出显示的部分是绊倒我的限制.在英语中,他们是:
type关键字)来绕过规则1.那么这与我的问题有何关系?
[Word16]只是另一种写作方式[] Word16.换句话说,[]是构造函数并且Word16是它的参数.
所以如果我们试着写:
instance IsString [Word16]
Run Code Online (Sandbox Code Playgroud)
这是一样的
instance IsString ([] Word16) where ...
Run Code Online (Sandbox Code Playgroud)
它不会起作用,因为它违反了规则1,正如编译器所指出的那样.
试图将其隐藏在类型同义词中
type String16 = [Word16]
instance IsString String16 where ...
Run Code Online (Sandbox Code Playgroud)
也不会工作,因为它违反了第2部分.
因此,在标准Haskell中实现它是不可能的[Word16](或者任何事物的列表)IsString.
输入...(鼓请)
newtype@ehird建议的解决方案是将其包装在newtype:
newtype String16 = String16 { unString16 :: [Word16] }
instance IsString String16 where ...
Run Code Online (Sandbox Code Playgroud)
它绕过了限制,因为String16它不再是别名,它是一种新类型(借口双关语)!唯一的缺点是我们必须手动包装和打开它,这很烦人.
以便携性为代价,我们可以通过灵活的实例完全放弃限制:
{-# LANGUAGE FlexibleInstances #-}
instance IsString [Word16] where ...
Run Code Online (Sandbox Code Playgroud)
这是@ [Daniel Wagner]建议的解决方案.
(顺便说一句,我最终foldl'围绕Data.Text.Internal创建了一个包装器,并在其上面写了哈希.)
| 归档时间: |
|
| 查看次数: |
7278 次 |
| 最近记录: |