Haskell 读取和表示指定要使用的数据类型的输入
我想读取一些数据,这些数据本身指定了要使用的数据类型 例如,假设可能存在如下用户输入:Haskell 读取和表示指定要使用的数据类型的输入,haskell,polymorphism,Haskell,Polymorphism,我想读取一些数据,这些数据本身指定了要使用的数据类型 例如,假设可能存在如下用户输入: 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)
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
s和Triple
s的阅读器:
readPair (w1:w2:[]) = Pair <$> maybeRead w1 <*> maybeRead w2
readTriple (w1:w2:w3:[]) = Triple <$> maybeRead w1 <*> maybeRead w2 <*> maybeRead w3
我想:
a
readT
如果用户的输入与a
不兼容,则应生成Nothing
readT
如果输入有效,则应生成仅(ta)
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
如果删除此检查,错误就会消失,但是如何验证用户输入是否与调用者选择的数据类型兼容?一个解决方案可能是使用单独的
readTInt
和readTDouble
,但我希望相同的readT
以多态方式工作,就像read
一样。问题是未定义::A
中的A
与readT
中的签名不同。GHC中提供了一种语言扩展,称为“ScopedTypeVariables”。一个更具可移植性的解决方案是引入一点额外的代码来显式地将类型绑定在一起,例如:
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
readT::(mvaluea,reada)=>String->Maybe(ta)
readT s=结果
哪里
结果=
格词
(tp:frm:rest)->
如果tp/=typename((const::a->Maybe(ta)->a)未定义的结果)
那就什么都没有了
其他情况下的frm
“pair”->TP readPair rest
“三重”->TT readTriple rest
_->没有
_->没有
这是对您的代码进行的一次非常快速和肮脏的修改,我很高兴更改可以更加优雅,但这应该会起作用。谢谢。这很有效。用
result
作为未定义Maybe(ta)->a
的参数的技巧是出人意料的。实际上,result
和undefined
都是const::a->Maybe(ta)->a
的参数,这迫使它们的类型以const
上显式类型签名给出的方式关联。但是是的,(未定义::可能(ta)->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.
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