[英]Haskell/Parsec: How do you use the functions in Text.Parsec.Indent?
[英]Haskell/Parsec: how do I use Text.Parsec.Token with Text.Parsec.Indent (from the indents package)
Haskell的Parsec的indents包提供了一種解析縮進式語言(如Haskell和Python)的方法。 它重新定義了Parser
類型,那么如何使用Parsec的Text.Parsec.Token
模塊導出的令牌解析器函數,這些函數是普通的Parser
類型?
Text.ParserCombinators.Parsec.IndentParser
和Text.ParserCombinators.Parsec.IndentParser.Token
Text.Parsec.Indent
0.3.3是一個提供單個模塊Text.Parsec.Indent
的新包 Parsec附帶了大量模塊 。 大多導出一堆有用解析器(例如newline
從Text.Parsec.Char
,它解析新行)或解析器組合(例如count np
從Text.Parsec.Combinator
,它運行解析器P,N次)
但是,模塊Text.Parsec.Token
想要導出由用戶參數化的函數和正在解析的語言的特征,因此,例如, braces p
函數將在解析'{'后運行解析器p在解析'}'之前,忽略注釋之類的東西,其語法取決於您的語言。
Text.Parsec.Token
實現這一點的方式是它導出一個函數makeTokenParser
,你調用它,給它你特定語言的參數(就像注釋的樣子),它返回一個包含所有函數的記錄。 Text.Parsec.Token
,適合您指定的語言。
當然,在縮進式語言中,這些需要進一步調整(也許?這里是我不確定的地方 - 我稍后會解釋)所以我注意到(可能是過時的)IndentParser包提供了一個模塊Text.ParserCombinators.Parsec.IndentParser.Token
,它看起來是Text.Parsec.Token
替代Text.Parsec.Token
。
我應該在某些時候提到所有的Parsec解析器都是monadic函數,所以它們用狀態做神奇的事情,這樣錯誤消息可以說出源文件中的哪一行和哪一行出現了錯誤
由於一些小的原因,在我看來,縮進包或多或少是當前版本的IndentParser,但是它沒有提供看起來像Text.ParserCombinators.Parsec.IndentParser.Token
的模塊,它只提供Text.Parsec.Indent
,所以我想知道如何從Text.Parsec.Token
獲取所有令牌解析器 (如reserved "something"
解析保留關鍵字“某事”,或者像我之前提到的那些braces
)。
在我看來,(新的) Text.Parsec.Indent
通過某種Text.Parsec.Indent
狀態魔法來處理源代碼的哪些列位,因此它不需要修改像whiteSpace
那樣的令牌解析器Text.Parsec.Token
,這可能是它沒有提供替換模塊的原因。 但是我遇到類型問題。
你看,沒有Text.Parsec.Indent
,我所有的解析器都是Parser Something
,其中Something是返回類型, Parser
是Text.Parsec.String中定義的類型別名
type Parser = Parsec String ()
但是使用Text.Parsec.Indent
,我使用自己的定義,而不是導入Text.Parsec.String
type Parser a = IndentParser String () a
這使我的所有解析器類型為IndentParser String () Something
,其中IndentParser在Text.Parsec.Indent中定義。 但是我從makeTokenParser
中的Text.Parsec.Token
獲取的令牌解析器的類型錯誤。
如果現在這沒有多大意義,那是因為我有點失落。 這里討論了類型問題。
我得到的錯誤是我嘗試用另一個替換上面的Parser
的一個定義,但是當我嘗試使用Text.Parsec.Token
一個令牌解析器時,我得到了編譯錯誤
Couldn't match expected type `Control.Monad.Trans.State.Lazy.State
Text.Parsec.Pos.SourcePos'
with actual type `Data.Functor.Identity.Identity'
Expected type: P.GenTokenParser
String
()
(Control.Monad.Trans.State.Lazy.State Text.Parsec.Pos.SourcePos)
Actual type: P.TokenParser ()
遺憾的是,上面的示例都沒有像Text.Parsec.Token中那樣使用令牌解析器。
聽起來你想讓你的解析器在任何地方被定義為類型
Parser Something
(其中Something是返回類型)並通過隱藏和重新定義通常從Text.Parsec.String
或類似方法導入的Parser
類型來實現此功能。 您仍然需要導入一些Text.Parsec.String
,以使Stream成為monad的實例; 用這條線做到這一點:
import Text.Parsec.String ()
您對Parser
定義是正確的。 或者等效地(對於那些在評論中聊天的人)你可以使用
import Control.Monad.State
import Text.Parsec.Pos (SourcePos)
type Parser = ParsecT String () (State SourcePos)
並且可能在顯示此定義的文件中import Text.Parsec.Indent (IndentParser)
。
您的問題是您正在查看編譯器錯誤消息的錯誤部分。 你專注於
Couldn't match expected type `State SourcePos' with actual type `Identity'
當你應該專注於
Expected type: P.GenTokenParser ...
Actual type: P.TokenParser ...
你從Text.Parsec.Token
“導入”解析器的Text.Parsec.Token
,你實際做的當然(正如你簡要提到的)首先定義一個記錄你的語言參數,然后將它傳遞給函數makeTokenParser
,它返回一個包含的記錄令牌解析器。
因此,您必須有一些看起來像這樣的行:
import qualified Text.Parsec.Token as P
beetleDef :: P.LanguageDef st
beetleDef =
haskellStyle {
parameters, parameters etc.
}
lexer :: P.TokenParser ()
lexer = P.makeTokenParser beetleDef
...但是P.LanguageDef st
只是GenLanguageDef String st Identity
,而P.TokenParser ()
實際上是GenTokenParser String () Identity
。
您必須將類型聲明更改為以下內容:
import Control.Monad.State
import Text.Parsec.Pos (SourcePos)
import qualified Text.Parsec.Token as P
beetleDef :: P.GenLanguageDef String st (State SourcePos)
beetleDef =
haskellStyle {
parameters, parameters etc.
}
lexer :: P.GenTokenParser String () (State SourcePos)
lexer = P.makeTokenParser beetleDef
......就是這樣! 這將允許您的“導入”令牌解析器具有類型ParsecT String () (State SourcePos) Something
,而不是Parsec String () Something
(它是ParsecT String () Identity Something
的別名),您的代碼現在應該編譯。
(為了最大限度的通用性,我假設您可能在一個文件中定義Parser
類型,該文件與您定義實際解析器函數的文件分開並導入。因此,這兩個重復的import
語句。)
非常感謝Daniel Fischer幫我解決這個問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.