我正在研究 Haskell 中的決議器,其定義來自G. Hutton、E. Meijer - Haskell 中的 Monadic Parsing。
data Parser a = Parser { parseWith :: String -> [(a, String)] }
instance Functor Parser where
fmap f (Parser p) = Parser $ \s -> [(f a, rest) | (a, rest) <- p s]
instance Applicative Parser where
pure x = Parser $ \s -> [(x, s)]
(Parser p1) <*> (Parser p2) = Parser $ \s -> [(f x, r2) | (f, r1) <- p1 s, (x, r2) <- p2 r1]
instance Monad Parser where
return = pure
p >>= f = Parser $ \s -> concatMap (\(x, r) -> parseWith (f x) r) $ parseWith p s
instance Alternative Parser where
empty = failure
p1 <|> p2 = Parser $ \s ->
case parseWith p1 s of
[] -> parseWith p2 s
res -> res
基本上我有一個(parsed :: a, remaining :: String)背景關系。
作為一個簡單的應用程式,我定義了以下 ADT 來決議:
data Arr = Arr Int [Int] -- len [values]
和一個可以Array從字串構造值的決議器,例如:
"5|12345" -> Arr 5 [1,2,3,4,5]
首先,為了決議n這些Array值(字串輸入包含n在第一個位置),例如:
"2 3|123 4|9876 2|55" -> [Arr 3 [1,2,3], Arr 4 [9,8,7,6]]
我可以執行以下操作:
arrayParse :: Parser Arr
arrayParse = do
len <- digitParse
vals <- exactly len digitParse
return $ Arr len vals
nArraysParse :: Parser [Arr]
nArraysParse = do
n <- digitParse
exactly n arrayParse
whereexactly n p通過應用p n時間構造一個新的決議器。
接下來,我想決議一個不同的方案。假設第一個字符表示定義陣列的子字串的長度,例如:
"9 3|123 4|9876 2|55" -> [Arr 3 [1,2,3], Arr 4 [9,8,7,6]]
這意味著我必須應用arrayParse第一個n字符(不包括|和空格)才能獲得前 2 個陣列:
3|123 -> 4 chars (excluding | and whitespace)
4|9876 -> 5 chars (excluding | and whitespace)
因此,應用決議器n時間很簡單:
exactly :: Int -> Parser a -> Parser [a]
exactly 0 _ = pure []
exactly n p = do
v <- p -- apply parser p once
v' <- exactly (n-1) p -- apply parser p n-1 times
return (v:v')
但是我如何表達在第一個n字符上應用決議器的意圖?
我最初的方法是這樣的:
foo :: Parser [Arr]
foo = do
n <- digitParse
substring <- consume n
-- what to do with substring?
-- can I apply arrayParse on it?
我應該如何處理這個問題?
uj5u.com熱心網友回復:
按照@jlwoodwa的建議,我設法實作了以下目標:
innerParse :: Parser a -> String -> Parser a
innerParse p s = case parseWith p s of
[(arr, "")] -> return arr
_ -> failure
substringParse :: Parser [Arr]
substringParse = do
n <- digitParse
substring <- consume n
innerParse (zeroOrMore arrayParse) substring
這適用于我的用例。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/386997.html
