2014-02-17 76 views
0

的情況下我有一個用戶定義的數據結構中的問題和Read匹配[字符]來讀取

首先這裏的情況是我的數據結構

data Nat = Null | Succ Nat 

我讀函數定義這樣

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. 

編程其他實例一樣EnumEqShow等是非常簡單的。 據我所知,Read預計的詮釋,但我不知道爲什麼;)

我想Readshow相反的,並採取了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)))"

謝謝!

+1

請爲您提供'Read'實例。 – crockeea

+0

如果你看看'Read'類,你會看到它定義了函數'readsPrec :: Int - > String - > [(a,String)]''。你的功能顯然沒有這種類型。第一個參數是一個優先級上下文,用於更開明的解析。返回類型必須是解析列表和其餘字符串。要將你的函數轉換成有效格式,你可以寫'readsPrec _ x = [(readNatNat x,「」)]' – user2407038

+0

@ user2407038的確。信不信由你,我只是在我的回答中這麼說,但我想我有點被帶走了! – AndrewC

回答

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應該如果解析失敗是一個小型解析器

  1. ,你應該返回[],不會導致錯誤。
  2. 您應該返回輸入其餘在剩餘的部分String
  3. (應該有可能解析列表)成功

3.列表和
2。返回剩餘部分:

此替代方法不適用於readsPrec應如何工作。列表[(a,String)]應該包含可能的解析和餘數字符串,因此readsPrec 5 "Null,Null,Succ Null]"應該是[(Null, ",Null,Succ Null]" ]。正如我試圖暗示那裏,未被消耗的輸入的其餘部分可以在解析值等的列表中使用

重要:
如果你不這樣做,你就更有可能從read "[Null,Succ Null]"得到錯誤的結果。

這是罕見的,將有不止一個可能的分析,但舉例來說,如果你已經決定,以顯示您Nat"0+1+1"你需要產生該輸入,列表[(Null,"+1+1"), (Succ Null, "+1"), (Succ (Succ Null), "") ]

這意味着你應該檢查您進出的方括號的數量,以便您可以返回剩餘字符串中的適當金額:readsPrec 3 "((Succ (Succ Null)))))"應該是[(Succ (Succ Null), "))"]

1.不要造成錯誤,返回[]

如果輸入的是不是一個有效的NAT,你需要返回[]。我發現三個有問題的線路:

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的信息)。