2017-06-21 25 views
-1

我不明白什麼呢的類型(例如)eol平均:百萬秒差距:如何聲明`eol`的解析文本和類型不[字符]

eol :: (MonadParsec e s m, Token s ~ Char) => m String 

,或者更好,我不明白如何使用EOL Text.Megaparsec.Text而不是Text.Megaparsec.String

我一直在嘗試使用學習如何使用Megaparsec遵循從真實世界Haskell Parsec(舊)教程(我實際上開始閱讀RWH教程之前發現Megaparsec存在)。我重寫了code of the first example以使用Megaparsec(見下文)。但我發現,當我試圖強制eol的類型爲Parser Text時,編譯器會拋出錯誤:Couldn't match type ‘[Char]’ with ‘Text’,我從中收集的是,我不能使用eolText,或者更可能的是,我不知道如何更改Token s ~ Char上下文從eol聲明中使用Token Text

{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE NoImplicitPrelude #-} 

module CSVParser (
    module CSVParser 
) where 

import Foundation 
import Data.Functor.Identity (Identity) 
import Text.Megaparsec 
import Text.Megaparsec.Text 
import Data.Text 

csvFile :: Parser [[Text]] 
csvFile = 
    do result <- many line 
     eof 
     return result 

line :: Parser [Text] 
line = 
    do result <- cells 
     --eol :: Parser Text -- uncommenting this line results in a compilation error 
     eol 
     return result 

cells :: Parser [Text] 
cells = 
    do first <- cellContent 
     next <- remainingCells 
     return (first : next) 

remainingCells = 
    (char ',' >> cells) 
    <|> return [] 

cellContent :: Parser Text 
cellContent = fromList <$> many (noneOf [',','\n']) 

parseCSV :: Text -> Either (ParseError (Token Text) Dec) [[Text]] 
parseCSV = parse csvFile "(unknown)" 
+0

你爲什麼寫'EOL ::分析器Text'當你忽略它的返回價值呢? –

+0

嗯,我這樣做是因爲我想知道如何改變它的類型。我想改變它的類型,因爲庫中的許多其他函數具有相同的類型聲明,例如'lowerChar ::(MonadParsec esm,Token s〜Char)=> m Char',我可能不想忽略它的返回值但將它約束爲「文本」(爲此我可以從'List <$> lowerChar',但看起來很醜陋,我想我可以直接改變類型,但我不知道或理解,如何)。主要是我的問題是'(MonadParsec e s m,Token s〜Char)=> m Char'。 – helq

回答

3

在類型:

eol :: (MonadParsec e s m, Token s ~ Char) => m String 

~是一種類型的等式約束,並且MonadParsecToken類型類由百萬秒差距定義。

  • MonadParsec e s m是斷言該類型m是一個monadic解析器讀取s類型的Stream和表示使用類型e
  • Token sErrorComponent誤差是基本類型的:如下它們可以粗略地解釋從流s

所以讀出的代幣,完整的類型可以被解釋爲:eol與「返回值」一個monadic解析器String,解析標記爲Char的流。

對於您的問題,其中大部分可以忽略。您正在運行到的問題是,eol返回String值作爲解析的結果,並且String不是Text,所以你不能讓一個eol(這是Parser String類型)是Parser Text類型,不管你多努力嘗試。

兩種解決方案都忽略了不必要的String返回值,如果你需要它作爲文本,將其轉換:

Data.Text.pack <$> eol 
+0

感謝您對'〜'的解釋,它確實對我有幫助。我認爲'Parsec Dec Text'類型(在導入Megaparsec時寫成'Parser'。Text')將'eol'的OUTPUT調整爲'Text',實際上它只是將'Text'強制作爲'eol'的INPUT流,所以我的(代碼)示例中的'eol'類型是'Parsec 12月文字[Char]'。但我想得到'Parsec Dec Text Text',這顯然是不可能的!因爲'eol'的類型是'(constraint)=> m [Char] === Parsec e s [Char]'。 – helq

+0

順便說一下,我還了解到'Token Text == Char',我沒有想到!因爲我看到'Text'和'[Char]'是不同的東西(它們是,'[Char]'是一個鏈表,而'Text'是其他東西),但從未想過它們的組成部分,它們只是'Char單曲。 現在有道理,'Parsec Dec Text [Char]'是'eol'完全有效的類型,我認爲它不是因爲'Text!= [Char]',但是它只是採用'eol: :(MonadParsec esm,Token s〜Char)=> m [Char]'並將'e'替換爲'Dec','s'替換'Text'(它符合'Token s〜Char'!)給了我們一個完全有效的類型。 – helq