我正在学习Haskell,我遇到了一个似乎无法解决的问题。基本上,我的用例如下。我正在处理一个字符串;如果它以"
字符开头,那么我想将其作为字符串返回("
剥离);否则,我想在其上返回read
的结果。换句话说:
parse "\"foo\"" -> "foo"
parse "3" -> 3
parse "1.5" -> 1.5
到目前为止,我已经尝试了以下方法。
parse :: String -> a
parse ('"':xs) = init xs -- strip closing '"'
parse string = read string
这会产生编译时错误Couldn't match expected type `a' with actual type `[Char]'
。 a
不应该匹配任何类型,包括[Char]
等复杂类型?
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
class Parse where parse :: String -> a
instance Read a => Parse a where parse = read
instance Parse String where parse = init . tail
这会编译,但会出现以下运行时错误:
Overlapping instances for Parse a0 arising from a use of `parse'
Matching instances:
instance Read a => Parse a -- Defined at parse.hs:5:14
instance Parse [Char] -- Defined at parse.hs:7:14
(The choice depends on the instantiation of `a0'
To pick the first instance above, use -XIncoherentInstances
when compiling the other instance declarations)
String
不是Read
的实例,所以我不确定它在何处看到重叠。
Illegal instance declaration for `Parse [Char]'
(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 `Parse [Char]'
和
Constraint is no smaller than the instance head
in the constraint: Read a
(Use -XUndecidableInstances to permit this)
In the instance declaration for `Parse a'
String
成为Read
我不知道该怎么做,文档对我来说并不是那么清楚。但是,如果我能弄明白的话,听起来这可能是正确的做法。但是有一个问题在我脑海中浮现:如果在一个模块中我将String
设为Read
的实例,即使我不导出相关位,它是否会改变整个应用程序的类?如果可以,那么我不确定我是否喜欢它的含义。
这就是我到目前为止所尝试过的。我的方法有误吗?它基本上是正确的,我只需要修复几个细节?请告诉我。
答案 0 :(得分:7)
不应
a
匹配任何类型,包括[Char]
等复杂类型?
它可以做到。这里的问题是谁可以选择a
是什么。您编写的类型是parse :: String -> a
,它是
parse :: forall a. String -> a
您应该将其读作:“来电者选择类型a
和String
s
,而parse s
会生成a
类型的值” 。这里的重要部分是调用者,而不是parse
,选择类型来替换a
。所以,如果你写
parse s = ""
这是一个错误,因为调用者可能会选择String
以外的类型!您还可以想象parse
可以选择的类型;这被称为存在类型,它对调用者如何使用生成的值有一些强烈的限制。
String
不是Read
的实例,所以我不确定它在何处看到重叠。
你错了:String
是Read
的一个实例。它使用以下两个实例:
instance Read Char -- Defined in ‘GHC.Read’
instance Read a => Read [a] -- Defined in ‘GHC.Read’
(回想一下type String = [Char]
。)例如,在ghci:
> read "\"foo\"" :: String
"foo"
也许这个实例足以满足您的目的!