我正在重做一个旧的家庭作业,以学习如何使用 Parsec,但我在为 Exits(和包含的数据类型)构建解析器时遇到了麻烦。所以首先我们得到一个包含房间列表的文件。每个房间都包含一个房间名称(下面——房间——)、一些描述或故事,然后是一个格式为 的出口列表(direction, destination)
。最终一个人会选择一个方向,然后你会查找房间名称并将玩家带到下一个房间。
-- Room --
Center
You are in a square room. There are doors to the
north, south, east, and west.
-- Exits --
North: North Hall
South: South Room
East: East Room
West: West Room
-- Room --
North Hall
You are in a hallway. There are doors to the north and south.
正如您所看到的,有些房间没有出口(我存储它的方式不是什么)。所以可能有可能退出。
我已经到了出口部分,并且在那一步之前我的所有解析器似乎都可以工作。问题在于处理可能没有出口或多个出口的事实。另外,我认为如何处理出口会影响我处理出口类型的方式(也就是出口类型可能会变成 Maybe [ Exit ]
无论如何,这是我的代码:
--module Loader
-- Game parser will go here
--
import Text.ParserCombinators.Parsec
import Data.List.Split
astory = unlines [" -- Room --",
"Cell",
"You have been locked in a dungeon cell. The prisoner next",
"to you whipsers, there's a tunnel behind the bed on the",
"south wall. Good Luck!",
"-- Exits --",
"South: Tunnel"]
type Rooms = [Room]
type Story = String
type Destination = String
data Exit = Exit { direction :: Direction, destination :: Destination } deriving (Ord, Show, Eq)
type Exits = [ Exit ]
data Room = Room { name :: String
, story :: String
, exits :: Exits
} deriving (Ord, Show, Eq)
data Direction = Nothing | North | South | East | West | Quit deriving (Ord, Show, Eq)
an_exit = "North: Tunnel \n"
a_full_exit = "-- Exits --\nSouth: Tunnel"
directionParser :: Parser Direction
directionParser = (string "South:" >> return South)
<|> (string "North:" >> return North)
<|> (string "East:" >> return East)
<|> (string "West:" >> return West)
parseExit :: Parser Exit
parseExit = do
direction <- directionParser
spaces
destination <- many (noneOf "\n")
return $ Exit direction destination
parseExits :: Parse Exits
parseExits = do
string "-- Exits --\n"
--oneRoom :: Parser Room
--oneRoom = do
-- string "--Room--\n"
-- name <- many (noneOf "\n")
-- newline
-- story <- manyTill anyChar (string "-- Exits --")
-- optionMaybe (string "-- Exits --")
-- exits <- optionMaybe $ many1 anyExits
-- return $ Room name story exits
--main = do
-- file <- readFile "cave.adventure"
-- let stories = splitOn "\n\n" file
-- mapM putStrLn stories
我目前在测试较小的解析器时注释掉了这个房间。
我的方法:
- 制作解析的 parseExits - 退出 - 和“许多 parseExit”。
- 如果 --Exit-- 没有发现解析器失败(我认为它返回 Nothing 然后)
- 在 oneRoom 解析器中,我查找 0 个或多个 parseExits 或 eof(因为我在 \n\n 上进行预拆分)
问题:
- 您如何根据 parsec docs optionMaybe 或 optional 做无或很多的技巧,但在哪里应用?在出口还是一个房间?易于访问的文档
- 我处理迷你解析器的方法是在 haskell 和 parsec 中处理这个问题的正确方法吗?
- 最后 oneRoom 当前接收到在 \n\n 上拆分的文件字符串,但我认为我可以将其包含在我的解析器中作为 oneRoom 解析器的最后一行,对吗?
- 在我的 oneRoom 解析器中,我目前正在将 Story 解析为以 - Exit 结尾的元素,但我不相信故事不会消耗下一个 - Exits - 或 eof?你如何让你的故事解析器在第一个 - 退出 - 它找到或 eof (或 \n\n 如果我解析完整文件)结束
我希望我的问题和代码足够清楚,如果不是,请让我知道如何澄清。提前致谢。