2012-11-23 124 views
2

當我被卡住時,我剛剛開始和哈斯克爾一起玩。Haskell中讀類的實例

我試圖讓我的新數據類型(我們稱之爲MyTypeRead類的實例。 Mytype是一個類型構造函數,所以它需要另一個類型作爲參數。我想寫這種代碼

instance (Read a) => Read (MyType a) where 
     readsPrec _ r = [foo (read r :: a), r] 

,但它給了我下面的錯誤

Could not deduce (Read a2) arising from a use of `read' from the context (Read a). 

我想,既然一個是Readable我可以推斷出它,但顯然我錯了。有任何想法嗎?

編輯: 我已經改變了以前的代碼

readsPrec _ r = [foo (read r :: a), ""] 

,所以如果我輸入:read "myString" :: MyType a它完美的罰款。 現在我希望如果在上下文中使用read "myString",我不應該指定要讀取的類型。但問題是,隨着

bar (read myString) a 

其中bar:: MyType a -> a -> MyType a,我 Ambiguos變量類型

是否有可能做這樣的事情而沒有得到那種類型的錯誤?

我希望現在更清楚,我試圖簡化代碼,但我希望我沒有忽略任何關鍵的東西。如果寫成

 
instance (Read a) => Read (MyType a) where 
     readsPrec _ r = [(foo (read r),r)] 

如果foo具有類型a -> MyType a

+1

請在此給出foo的類型,只是爲了完整。 –

+0

foo,它實際上是一個解析器,它在我試圖簡化的代碼中更復雜一些。現在它實際上編譯即使沒有ScopedTypeVariables,但正如你在另一篇文章中說的,我可能誤解了readPresc的工作方式,因爲現在我得到了 異常:Prelude.read:沒有解析 當我嘗試讀取一個字符串爲MyType。 – user1544128

+0

好的,所以在我的情況下是正確的應該是[富(讀r :: a),「」],希望將有助於其他一些新手:) – user1544128

回答

7

的代碼實際上typechecks。編譯器可以從預期的類型簽名readsPrec中找出對foo的調用應該返回MyType a,因此(按類型foo),表達read r應該具有類型a

但是,爲什麼當你用:: a註解時,它會失敗?因爲類型變量對於它們出現的類型簽名是局部的。所以a與實例heade中的a完全無關,並且read r :: a實際上是在說:表達式read r可以具有任意類型。但是任意類型沒有Read實例,因此是錯誤消息。在消息中,編譯器將內部a重命名爲a2以避免名稱衝突。

但是,如果您將{-# LANGUAGE ScopedTypeVariables #-}添加到模塊標頭,您的代碼可以按預期工作。現在,read r :: a中的a指的是實例頭中的a類型,並且一切順利。

請注意,您沒有正確使用readsPrec,但我想這不是問題的一部分。

+0

我添加了ScopedTypeVariables,它實際上編譯,但是當我嘗試閱讀時,我得到了Exception:Prelude.read:no parse。 你能解釋一下我沒有正確使用readsPrec的事實嗎?我想我只需要返回一個帶有MyType和解析字符串的1元組的列表,但顯然我又錯了。 – user1544128

+0

您不應該返回已解析的字符串,而應該返回尚未解析的字符串。此外,該列表應包含所有可能的字符串解析(如果有幾個)和空列表(如果沒有)(並且沒有例外)。 一般來說,如果你實現'readsPrec',很可能你還應該使用'readsPrec'作爲'a'。 –