我想读一些本身指定要使用的数据类型的数据。
例如,我们假设可能存在以下用户输入:
integer pair 1 2
integer triple 1 2 3
real pair 1 2
real triple 1 2 3
并且有一种数据类型来表示它:
data (MValue a) => T a = TP (Pair a) | TT (Triple a)
deriving (Show, Eq)
data Pair a = Pair a a deriving (Show, Eq)
data Triple a = Triple a a a deriving (Show, Eq)
允许的值类型必须属于MValue
类:
class (Num a, Read a) => MValue a where
typename :: a -> String
readval :: [String] -> Maybe a
instance MValue Int where
typename _ = "integer"
readval [s] = maybeRead s
readval _ = Nothing
instance MValue Double where
typename _ = "real"
readval [s] = maybeRead s
readval _ = Nothing
maybeRead s =
case reads s of
[(x,_)] -> Just x
_ -> Nothing
我可以轻松为Pair
和Triple
s:
readPair (w1:w2:[]) = Pair <$> maybeRead w1 <*> maybeRead w2
readTriple (w1:w2:w3:[]) = Triple <$> maybeRead w1 <*> maybeRead w2 <*> maybeRead w3
问题是如何为整个T a
类型编写多态读取器?:
readT :: (MValue a, Read a) => String -> Maybe (T a)
我想:
a
。readT
不兼容,则Nothing
应生成a
。readT
应生成Just (T a)
。天真的实施
readT :: (MValue a, Read a) => String -> Maybe (T a)
readT s =
case words s of
(tp:frm:rest) ->
if tp /= typename (undefined :: a)
then Nothing
else case frm of
"pair" -> TP <$> readPair rest
"triple" -> TT <$> readTriple rest
_ -> Nothing
_ -> Nothing
在行if tp /= typename (undefined :: a)
中出错:
rd.hs:45:17:
Ambiguous type variable `a' in the constraint:
`MValue a' arising from a use of `typename' at rd.hs:45:17-41
Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
如果我删除此检查错误就会消失,但如何验证用户输入是否与调用者选择的数据类型兼容?解决方案可能是单独的readTInt
和readTDouble
,但我希望同一个readT
以与read
相同的方式进行多态处理。
答案 0 :(得分:5)
问题是a
中的undefined :: a
与a
签名中的readT
不一样readT :: (MValue a, Read a) => String -> Maybe (T a)
readT s = result
where
result =
case words s of
(tp:frm:rest) ->
if tp /= typename ((const :: a -> Maybe (T a) -> a) undefined result)
then Nothing
else case frm of
"pair" -> TP <$> readPair rest
"triple" -> TT <$> readTriple rest
_ -> Nothing
_ -> Nothing
。 GHC中有一种语言扩展可以实现,称为“ScopedTypeVariables”。一个更便携的解决方案是引入一些额外的代码来明确地将类型绑定在一起,例如:
{{1}}
这是对代码的一个非常快速和肮脏的修改,我可以更优雅地进行更改,但这应该可行。