我遇到了用户定义的数据结构和Read
首先是我的数据结构
data Nat = Null | Succ Nat
我的read函数定义如下
readNatNat :: String -> Nat
readNatNat xs |first == '(' = readNatNat (tail xs)
|first == ' ' = readNatNat (tail xs)
|firstFour == "Succ" = (Succ (readNatNat(drop 4 xs)))
|firstFour == "Null" = Null
|b `elem` [0..] = toNatInt(b)
where b = (read(xs)::Int)
first = head xs
firstFour = take 4 xs
toNatInt :: Int -> Nat
toNatInt x | x==0 = Null
| x<0 = error "Unter Null gibts kein Int 2 Nat"
| otherwise = Succ(toNatInt(x-1))
readNatNat
作为独立函数按预期工作,但是当我想将它与Read
实例一起使用并尝试加载它时,我得到以下异常
Couldn't match type `[Char]' with `Int'
Expected type: Int -> ReadS Nat
Actual type: String -> Nat
In the expression: readNatNat
In an equation for `readsPrec': readsPrec = readNatNat
In the instance declaration for `Read Nat'
Failed, modules loaded: none.
对Enum
,Eq
,Show
等其他实例进行编程非常简单。
我理解Read
期望一个Int,但我不知道为什么;)
我认为Read
与show
相反,并使用String
并将其解析为我的数据结构。
我像这样定义了Show
instance Show Nat where
show (Succ a) = showsRealSucc(Succ a)
show Null = show "Null"
showsRealSucc :: Nat -> String
showsRealSucc Null = "Null"
showsRealSucc (Succ a) = (if a/= Null then ("Succ ("++showsRealSucc(a)++")")
else "Succ Null")
了解Nat
:
它是自然数的表示,所以当我输入readNatNat "3"
输出时
"(Succ(Succ(Succ Null)))"
提前致谢!!
答案 0 :(得分:2)
readsPrec
采用优先级参数readsPrec :: Int -> ReadS a
type ReadS a = String -> [(a,String)]
所以
readsPrec :: Int -> String -> [(a,String)]
readsPrec
需要额外的Int
参数来指示周围上下文中的优先级,因此,例如,如果您正在阅读Just Null
,则周围的优先级为10,即函数应用程序。
在您的情况下,我认为您可以使用效用函数readParen :: Bool -> ReadS a -> ReadS a
来处理:
instance Read Nat where
readsPrec prec = readParen prec natReads where
natReads xs = [(readNatNat xs,"")]
readsPrec
应该是迷你解析器[]
,不要导致错误。String
部分 第3。成功列表和
2.退还剩余部分:
这种解决方法不适用于readsPrec
应该如何工作。列表[(a,String)]
应包含可能的解析和余数字符串,以便readsPrec 5 "Null,Null,Succ Null]"
应为[(Null, ",Null,Succ Null]" ]
。正如我试图在那里暗示的那样,在解析值列表等时可以使用剩余的未消耗输入。
重要的:
如果你不这样做,你更有可能从read "[Null,Succ Null]"
得到错误的结果。
很少会有多个可能的解析,但是,例如,如果您决定将Nat
值显示为"0+1+1"
,则需要为该输入生成列表{ {1}}
这意味着您应该检查进出方式的括号数量,以便在余数字符串中返回适当的金额:[(Null,"+1+1"), (Succ Null, "+1"), (Succ (Succ Null), "") ]
应为readsPrec 3 "((Succ (Succ Null)))))"
。
<强> 1。不要导致错误,请返回[]
如果输入不是有效的Nat,则需要返回[(Succ (Succ Null), "))"]
。我发现了三个问题:
[]
您应该将这些转换为支票,然后回答 where b = (read(xs)::Int) -- could crash
first = head xs -- could crash
| x<0 = error "Unter Null gibts kein Int 2 Nat" -- crashes
。
可悲的是,我认为这意味着你需要在某种程度上重写解析器。好消息是它本质上是递归的,[]
可以为你完成大部分工作。一个有用的辅助函数是
readParen False
这样,当您找到fmapPairs :: (a -> b) -> [(a,String)] -> [(a,String)]
fmapPairs f pairs = [(f a,xs) | (a,xs) <- pairs]
时,可以fmapPairs Succ (readParen False)
余下的"Succ"
。让我知道你是否需要更多的提示来完成这项工作(我认为你已经证明了你的能力,而且现在你知道更多关于readsPrec
的信息,这是一个很好的练习。)