2011-06-16 75 views
10

在下面的類型聲明中約束(Stream s Identity t)是什麼意思?Parsec函數'parse'和類'Stream'的類型簽名

parse :: (Stream s Identity t) 
    => Parsec s() a -> SourceName -> s -> Either ParseError a 

什麼是Stream在下面的類聲明中是什麼意思。我完全迷失了。

class Monad m => Stream s m t | s -> t where 

當我使用秒差距,我得到與類型簽名(xxx :: yyy)所有的時間卡紙。我總是跳過簽名,將src加載到ghci中,然後將類型簽名複製回我的.hs文件。它有效,但我仍不明白這些簽名是什麼。


編輯:更多關於我的問題的觀點。

我仍然感到困惑類型簽名的「語境」:

(Show a) => 

意味着a必須Show類的實例。

(Stream s Identity t) => 

這是什麼「語境」的意思,因爲t=>


我有很多不同的解析器的運行後一直沒有露面,所以我寫了一個彎曲函數運行任何那些具有真實文件的解析器。但問題來了:

這是我的代碼,它不能被加載,我怎麼能使它工作?

module RunParse where 
import System.IO 
import Data.Functor.Identity (Identity) 
import Text.Parsec.Prim (Parsec, parse, Stream) 

--what should I write "runIOParse :: ..." 
--runIOParse :: (Stream s Identity t, Show a) => Parsec s() a -> String -> IO() 
runIOParse pa filename = 
    do 
    inh <- openFile filename ReadMode 
    outh <- openFile (filename ++ ".parseout") WriteMode 
    instr <- hGetContents inh 
    let result = show $ parse pa filename instr 
    hPutStr outh result 
    hClose inh 
    hClose outh 
+0

你在爲你的組合符聲明類型嗎?如果沒有,也許你會得到含糊不清的錯誤? – 2011-06-16 12:29:08

回答

12

約束:(流S標識T)意味着什麼?

這意味着輸入s你的解析器的工作(即[Char])必須Stream類的一個實例。在documentation中,您看到[Char]確實是Stream的一個實例,因爲任何列表都是。

參數t是令牌類型,它通常是Char並且通過s determinded,作爲規定的函數依賴s -> t

但是不要太擔心這個Stream類型類。它僅用於爲任何類似Stream的類型提供統一的接口,例如列表或ByteStrings。

什麼是流

流是一個簡單的類型類。它具有uncons函數,該函數返回輸入的頭部和尾部,並以Maybe包裝的元組的形式返回。通常你不需要這個功能。據我所知,只有在最基本的解析器中才需要它,如tokenPrimEx

編輯:

這是什麼 '語境' 的意思,因爲T一直沒有露面後=>

看一看functional dependencies。 '=>'之後t從不顯示,因爲它由s確定。 這意味着您可以在任何s上使用uncons

這是我的代碼,它不能被加載,我怎麼能使它工作?

簡單:爲Text.Parsec.String添加導入語句,該語句爲Stream [tok] m tok定義缺少的實例。這裏的文檔可能會更清晰一些,因爲看起來好像這個實例是在Text.Parsec.Prim中定義的。

或者導入整個Parsec庫(import Text.Parsec) - 這是我總是這樣做的。

+0

我覺得它接近答案,你能更詳細地解釋'(Stream s Identity t)'的語法結構嗎?非常感謝!附:我編輯了我的問題。 – Nybble 2011-06-17 02:41:57

+0

試圖回答您的編輯。 – bzn 2011-06-17 09:25:21

11

Stream類型類是類列表數據結構的抽象類。 Parsec的早期版本僅用於解析令牌列表(例如,String[Char]的同義詞,因此Char是令牌類型),這可能是非常低效的表示形式。現在,在Haskell中最大量的輸入被處理爲TextByteString類型,它們不是列表,但可以與它們很相似。

因此,舉例來說,你提到

parse :: (Stream s Identity t) 
    => Parsec s() a -> SourceName -> s -> Either ParseError a 

這種類型的一些特將

parse1 :: Parsec String() a -> SourceName -> String -> Either ParseError a 
parse2 :: Parsec Text() a -> SourceName -> Text -> Either ParseError a 
parse3 :: Parsec ByteString() a -> SourceName -> ByteString -> Either ParseError a 

甚至,如果你有一個令牌類型MyToken一個單獨的詞法分析器:

parse4 :: Parsec [MyToken]() a -> SourceName -> [MyToken] -> Either ParseError a 

其中,只有輸入的第一個和最後一個使用實際列表,但中間兩個使用其他Stream實例,它們的行爲足以像Parsec的列表一起使用它們。

你甚至可以聲明自己Stream實例,因此,如果您輸入的作用排序列表類似的一些其他類型的,你可以寫一個實例,實現uncons功能,秒差距將與您的工作類型,如好。