我正在尝试使用parsec库在haskell中实现语法,但是我遇到了预期的V问题.语法中定义的实际类型,我知道我的问题的答案无疑是简单/明显的,但是有一些我不理解的东西......
随后是数据声明的摘录(应该足以诊断):
data Expr1 = SeqOfExpr1 [Expr1]
| Lambda Expr8 Expr1
| List Expr2 Expr1
| If Expr2 Expr1 Expr1
| Expr2
deriving (Show)
data Expr2 = SeqOfExpr3 [Expr3]
deriving (Show)
data Expr3 = SeqOfExpr4 [Expr4]
deriving (Show)
----------------------------Redundant Code Omitted------------------------------
expr1 :: Parser Expr1
expr1 = declaration
<|> list
<|> ifStmt
<|> expr2
declaration :: Parser Expr1
declaration =
do reservedOp "\\"
var <- name
reservedOp "->"
expr <- expr1
return $ Lambda var expr
list :: Parser Expr1 …Run Code Online (Sandbox Code Playgroud) 我正在阅读 WikiBook“在 48 小时内为自己编写一个计划”。
Haskell 库 Parsec 用于解析基本表达式,例如数字(如下面的代码所示)。
import Lib
import Text.ParserCombinators.Parsec hiding (spaces)
import System.Environment
import Control.Monad
import Data.Typeable ( typeOf )
import Debug.Trace
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Integer
| String String
| Bool Bool
deriving Show
-- ...
parseNumber :: Parser LispVal
parseNumber = do
x <- many1 digit
return $ Number (read x)
Run Code Online (Sandbox Code Playgroud)
书中的一个练习要求读者parseNumber改用>>=符号重写。但是,我不断遇到看起来很可怕的类型不匹配错误。有人可以告诉我如何使用>>=符号重写函数吗?或者至少给我一个提示?
是否有一些'日期解析器'库可以用于日期FParsec对字符串的作用?
也就是说,您要么指定规则,要么匹配它们以识别提供的模式.
相反,是否有任何库可以根据一些解析规则生成日期?这个想法是为用户提供"实时"完成,以指导他进行有效的未来fparsec匹配.
(生成解析的这个问题在僻静的解析圈中有一个名字吗?)
我正在Haskell中编写一个反引号,我需要一个解析有效Haskell变量标识符的Parsec组合器.
是否已经在quasiquoting库中实现了一个或者我需要编写自己的库?
我希望我不需要复制/粘贴http://www.haskell.org/haskellwiki/Quasiquotation中的ident实现.
我刚刚开始学习使用Parsec解析字符串,我遇到了以下问题,我无法解决这个问题:
以下代码包含三个解析器运行,其中两个显然会失败.奇怪的是,我的自定义失败消息只会在第二次运行时发生,而不是在第三次运行时发生.
import Text.Parsec
import Text.Parsec.String
ps :: Parser String
ps = (string "123") <|> (string "456") <|> fail "my-failure"
main = do
putStrLn $ "A: " ++ show (parse ps "" "123")
putStrLn $ "\nB: " ++ show (parse ps "" "789")
putStrLn $ "\nC: " ++ show (parse ps "" "45x")
Run Code Online (Sandbox Code Playgroud)
输出:
A: Right "123"
B: Left (line 1, column 1):
unexpected "7"
expecting "123" or "456"
my-failure
C: Left (line 1, column 1):
unexpected "x"
expecting "456" …Run Code Online (Sandbox Code Playgroud) 我正在尝试解析sgf文件(描述go游戏的文件).在这些文件中有表单的键值对(在sgf规范中,它们被称为属性id和属性值,但我使用键和值,希望人们在阅读标题时知道我在说什么):
key[value]
Run Code Online (Sandbox Code Playgroud)
要么
key[value1][value2]...[valuen]
Run Code Online (Sandbox Code Playgroud)
也就是说,可能有一个或多个值.问题是值的类型取决于键.因此,例如,如果关键是B(在游戏中玩黑石).该值应该是由两个字母描述的坐标,例如:B[ab].它也可能是关键是AB(用于添加一些黑色宝石,用于设置棋盘),然后该值是一个坐标列表,如下所示:AB[ab][cd][fg].也可能是关键是C(评论).然后该值只是一个字符串C[this is a comment].
当然,这可以通过类型来描述
type Property = (String, [String])
Run Code Online (Sandbox Code Playgroud)
但我认为拥有类似的东西会更好
data Property = B Coordinate | AB [Coordinate] | C String ...
Run Code Online (Sandbox Code Playgroud)
或者也许其他类型更好地利用类型系统,并且不需要我一直转换为字符串和从字符串转换.
问题是,然后我需要一个解析器,根据键类型返回一个不同的值类型,但我认为这会导致类型问题,因为解析器只能返回一种类型的值.
你会如何解析这样的东西?
我发现在Haskell中学习Parsec很难,所以我正在尝试创建我的大学项目(一个用表格解析文件的解析器)
x=3
y=4
z=x+y
badluck=(x+sqrt(z)*7)
Run Code Online (Sandbox Code Playgroud)
我设法写了一个函数,从文件中获取所有内容并验证文件,我坚持让x成为变量名.我知道在javascript中它是eval但我在Haskell中找不到类似的东西.请帮忙!
这是我到目前为止所做的事情:
ischarorscore :: Char -> Bool
ischarorscore a = if ((a>='A' && a<='Z') || (a>='a' && a<='z') || a=='_')
then True
else False
ischarscoredigit :: Char -> Bool
ischarscoredigit a = if ((a>='A' && a<='Z') ||
(a>='a' && a<='z') ||
a=='_' ||
a>='0' && a<='9') then True else False
isvar :: String -> Bool
isvar [] = False
isvar (h:t) = if (ischarorscore h) then (isvarbody t) else False
isvarbody :: String -> Bool …Run Code Online (Sandbox Code Playgroud) 我已经定义了以下自定义解析器:
newtype St = St Int
type TxsParser = ParsecT String St (State St)
Run Code Online (Sandbox Code Playgroud)
现在为了能够运行这个解析器,我必须使用该runParserT函数.
runParserT :: Stream s m t
=> ParsecT s u m a
-> u
-> SourceName
-> s
-> m (Either ParseError a)
Run Code Online (Sandbox Code Playgroud)
哪个实例化到我的自定义解析器读取:
runParserT :: ParsecT String St (State St) a
-> St
-> SourceName
-> String
-> State St (Either ParseError a)
Run Code Online (Sandbox Code Playgroud)
但这意味着如果我想评估runParserT(状态monad)的结果,我必须提供另一个初始状态(St在这种情况下为类型).例如:
evalState (runParserT myParser (St 0) fp input) (St 0)
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但我必须重复两次状态似乎是错误的.这是否意味着混合ParsecT和Statemonad不是一个好主意?
如果我有一个解析器将一串由空格分隔的数字读取到整数列表中,那么如何处理尾随空格?目前我有:
\nrow :: Parser [Int]\nrow = do\n optional spaces\n f <- (many (oneOf "0123456789"))\n r <- ((char ' ') >> row) <|> pure []\n pure (read f:r)\nRun Code Online (Sandbox Code Playgroud)\n对于没有尾随空格的字符串效果很好,但对于尾随空格则失败。
\n>\xce\xbb= parse row "" " 2 0 12 3 7"\nRight [2,0,12,3,7]\n\n>\xce\xbb= parse row "" " 2 0 12 3 7 "\nRight [2,0,12,3,7,*** Exception: Prelude.read: no parse\nRun Code Online (Sandbox Code Playgroud)\n这个问题的解决方案是什么,更重要的是,我如何拥有 if'\\n'被消耗然后解析器返回的条件[]
编辑:\n通过阅读@amalloy的答案和parsec源代码,我认为添加一个在这里工作的版本很有用(尽管,@amalloy的建议不要尝试滚动现有函数更有意义)
\nrow :: Parser [Int]\nrow = do\n spaces\n f <- (read <$> many1 digit)\n do\n …Run Code Online (Sandbox Code Playgroud)