2017-06-21 22 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