【发布时间】:2012-09-02 13:59:52
【问题描述】:
我正在尝试在 Haskell 中实现词法分析器。为了方便控制台输入和输出,我使用了中间数据类型 Transition Table。
type TransitionTable = [(Int, Transitions String Int)]
type Transitions a b = [(a, b)]
我想从用户那里获取所有状态和转换的输入。我不想事先了解州的总数。我希望它继续输入每个状态的转换,直到用户输入 "--" 。如果用户键入 "---",则丢弃当前状态并终止输入。
经过多次尝试,我想出了这个,我认为这是可怕的代码。
-- |A function to emulate the while loop for easy IO functionality.
-- Defination:- while @comparator @func @start:
-- *comparator @arg: A function which returns True or False on the basis of @arg.
-- The loop stops when False is returned.
-- *func: The function which is executed repeadly.
-- It is responsible for returning the next @arg for the comparator on the basis of the current @arg.
-- *start: The starting value of @arg to pass to the comparator.
while :: (Monad m) => (a -> Bool) -> (a -> m a) -> a -> m a
while comparator func start =
if comparator start then do
nxt <- func start
while comparator func nxt
else
return start
-- |A modification of putStr which flushes out stdout. Corrents buffer problems.
myPutStr :: String -> IO ()
myPutStr str = putStr str >> hFlush stdout >> return ()
-- Takes input from the console to generate a TransitionTable.
inputTransitionTable :: IO TransitionTable
inputTransitionTable = do
putStrLn "Type -- for next state and --- for completing input entering."
retVal <- while notFinished takeInfo (0, [])
return (snd retVal)
where
-- Returns True when input entry is over.
notFinished (i, _) = i > -1
-- Takes the current state number and the incomplete corrosponding transition table which is populated
-- with user input. Input ends when user enters "---". State number is set to -1 when input is over.
takeInfo (i, states) = do
putStrLn ("Adding transitions to state " ++ show i ++ ": ")
retVal <- while entryNotFinished takeStateInfo ("", [])
let (inpStr, stateInfo) = retVal
case inpStr == "---" of
True -> return (-1, states)
False -> return (i+1, states ++ [(i, stateInfo)])
-- Checks if input entry is over. Returns False if finished.
entryNotFinished (s, _)
| s == "--" || s == "---" = False
| otherwise = True
-- Takes the input state number along with the corresponding transitions.
-- Input ends when the user enters "--".
takeStateInfo (str, state_info) = do
myPutStr "\tEnter transitions symbol: "
symbol <- getLine
if symbol == "--" || symbol == "---" then
return (symbol, state_info)
else do
myPutStr "\t\tEnter the transition state number: "
state' <- getLine
let state = read state' :: Int
return (str, (symbol, state):state_info)
基本上是这样运行的:
*Main> x <- inputTransitionTable
Type -- for next state and --- for completing input entering.
Adding transitions to state 0:
Enter transitions symbol: a
Enter the transition state number: 1
Enter transitions symbol: b
Enter the transition state number: 2
Enter transitions symbol: --
Adding transitions to state 1:
Enter transitions symbol: a
Enter the transition state number: 2
Enter transitions symbol: b
Enter the transition state number: 3
Enter transitions symbol: --
Adding transitions to state 2:
Enter transitions symbol: a
Enter the transition state number: 3
Enter transitions symbol: --
Adding transitions to state 3:
Enter transitions symbol: --
Adding transitions to state 4:
Enter transitions symbol: ---
(0.03 secs, 344420 bytes)
-- Output
*Main> prettyPrintTransitionTable x
State Transitions
0 ("b",2) ("a",1)
1 ("b",3) ("a",2)
2 ("a",3)
3
有没有更好的方法来做到这一点?
【问题讨论】:
-
就我个人而言,我认为this 一点也不可怕。你在
inputTransitionTable中有一些...少于惯用代码,但循环部分对我来说似乎很好,轮子改造除外。 -
@C.A.McCann 哦,谢谢。在我的辩护中,我仍然是一个初学者。我对代码的问题是它非常扭曲并且嵌套太多。我实际上是在将它与我用 C++ 编写的代码进行比较,虽然所有纯的 haskell 位都比 C++ 等效的更简单和优雅,但这里的 haskell 代码严重丢失。
-
老实说,它可能比我的许多初学者代码要好。这些扭曲在很大程度上是肤浅的,可以很容易地整理——如果它有效,那么它根本没有错误。如果您希望代码稍微扭曲一下,那么对于 codereview.stackexchange.com 可能比 SO 更合适。如果你把它贴在那里,如果没有其他人先发,我今晚就试试。
-
看看 Parsec - Real World Haskel 中提供的不错的教程:book.realworldhaskell.org/read/using-parsec.html
-
就标题而言:参见 Control Monad 中的 forever 函数:haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/…
标签: haskell functional-programming