我正在学习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
,所以我不太确定它在哪里看到重叠.
顺便说一句,pragma是存在的,因为否则我会遇到编译时错误:
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
,即使我不导出相关位,它是否会改变整个应用程序的类?如果可以,那么我不确定我喜欢它的含义.
这就是我到目前为止所尝试的内容.我的方法有误吗?它基本上是正确的,我只需要修复几个细节?请告诉我.
不应该
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"
也许这个实例足以满足您的目的!