问题描述
我正在编写一个使用UTF-16字符串的应用程序,并且使用重载的字符串扩展我尝试为它创建一个实例IsString([] Word16)其中...
它不起作用,因为它违反了规则1,正如编译器所指出的那样。
试图将它隐藏在类型的同义词中
type String16 = [Word16]
instance IsString String16 where ...
也不管用,因为它违反了第2部分。
因此,不可能得到 [Word16] (或者任何 列表),以在标准Haskell中实现 IsString 。
输入...(请滚动)
解决方案#1: newtype
@ehird建议的解决方案是w在 newtype 中说唱它:
newtype String16 = String16 {unString16: :[Word16]}
实例IsString String16其中...
它解决了限制因为 String16 不再是别名,它是一种新类型(原谅双关语)!这是唯一的缺点是我们必须手动打包和解包,这很烦人。
解决方案#2:灵活的实例
$
$ b
{ - #LANGUAGE FlexibleInstances# - }
实例IsString [Word16]其中...
这是@ [丹尼尔瓦格纳]建议的解决方案。
(顺便说一下,我最终制作了一个 foldl'封装在并在其上编写散列。)
I'm writing an application that uses UTF-16 strings, and to make use of the overloaded strings extension I tried to make an IsString instance for it:
import Data.Word ( Word16 ) import Data.String ( IsString(fromString) ) type String16 = [Word16] instance IsString [Word16] where fromString = encodeUTF16 encodeUTF16 :: String -> String16
The problem is, when I try to compile the module, GHC 7.0.3 complains:
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]'
If I comment out the instance declaration, it compiles successfully.
Why is this rejected? The instance for [Char] looks pretty much like the same thing, yet it compiles fine. Is there something I've missed?
After having a look through the GHC manuals and around the Haskell wiki (especially the List instance page), I've got a better idea of how this works. Here's a summary of what I've learned:
Problem
The Haskell Report defines an instance declaration like this:
The parts highlighted in bold are the restrictions that tripped me up. In English, they are:
- Anything after the type constructor must be a type variable.
- You can't use a type alias (using the type keyword) to get around rule 1.
So how does this relate to my problem?
[Word16] is just another way of writing [] Word16. In other words, [] is the constructor and Word16 is its argument.
So if we try to write:
instance IsString [Word16]
which is the same as
instance IsString ([] Word16) where ...
it won't work, because it violates rule 1, as the compiler kindly points out.
Trying to hide it in a type synonym with
type String16 = [Word16] instance IsString String16 where ...
won't work either, because it violates part 2.
So as it stands, it is impossible to get [Word16] (or a list of anything, for that matter) to implement IsString in standard Haskell.
Enter... (drumroll please)
Solution #1: newtype
The solution @ehird suggested is to wrap it in a newtype:
newtype String16 = String16 { unString16 :: [Word16] } instance IsString String16 where ...
It gets around the restrictions because String16 is no longer an alias, it's a new type (excuse the pun)! The only downside to this is we then have to wrap and unwrap it manually, which is annoying.
Solution #2: Flexible instances
At the expense of portability, we can drop the restriction altogether with flexible instances:
{-# LANGUAGE FlexibleInstances #-} instance IsString [Word16] where ...
This was the solution @[Daniel Wagner] suggested.
(By the way, I ended up making a foldl' wrapper around Data.Text.Internal and writing the hash on top of that.)
这篇关于“非法实例声明”当声明IsString的实例时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!