假設我有一個這樣的程式:
let words = ["foo", "bar", "baz", "qux"]
for (var i = 0; i < words.length; i ) {
console.log(words[i])
}
我想過濾 AST 并只保留文字。如何遍歷 AST 以僅保留“foo”、“bar”等?
literals :: JSAST -> [String]
literals (JSAstProgram statements) = undefined
literals _ = []
未定義的行應該過濾[JSStatement],然后尋找可能的運算式。如果找到運算式,請檢查是否有文字。最后,從 a JSStatement->映射串列String。
尋找可能的運算式是我現在的問題。我可以模式匹配:
f :: JSStatement -> a
f (JSLet _ expression _) = undefined
f (JSConstant _ expression _) = undefined
f (JsDoWhile _ _ _ _ expression _ _) = undefined
... etc
然后同樣的事情尋找文字:
g :: JSExpression -> a
g (JSLiteral _ literal) = undefined
g (JSStringLiteral _ literal) = undefined
g (JSArrayLiteral _ literal _) = undefined
... etc
然而,這是非常冗長的,我覺得那里有更好的東西。如何遍歷 AST 并以簡潔明了的方式僅過濾掉文字?
uj5u.com熱心網友回復:
中的所有型別Language.JavaScript.Parser都是 的實體Data.Data,一個用于對資料建構式進行一般折疊的類。您可以使用gmapQ此類中的一個函式來遍歷結構,并cast確定何時找到了感興趣的節點。下面是一個更簡單的示例 AST 型別的實作。
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data (Data, gmapQ)
import Data.Typeable (cast)
data Lit = S String | I Int deriving Data
data Expr = Sum Expr Expr | LitExpr Lit deriving Data
data Statement = Stmt [Expr] deriving Data
data AST = AST [Statement] deriving Data
strings :: AST -> [String]
strings = concat . gmapQ go
where go :: Data d => d -> [String]
go x = case cast x of
Nothing -> concat $ gmapQ go x
Just (I _) -> []
Just (S s) -> [s]
λ> strings (AST [Stmt [], Stmt [LitExpr (S "x"), Sum (LitExpr (I 5)) (LitExpr (S "y")), LitExpr (S "z")]])
["x","y","z"]
請注意,我需要給出go一個明確的型別簽名。我認為這是因為否則 GHC 會推斷遞回呼叫go必須使用與d封閉呼叫相同的約束,但當然我們需要它們不同。
uj5u.com熱心網友回復:
你是對的,這些東西通常都是樣板檔案;Haskell 擁有優秀的庫,可以讓您輕松撰寫此類函式。我的最愛之一是 uniplate:https ://hackage.haskell.org/package/uniplate
按照@amalloy 的示例,以下是使用 Uniplate 進行編碼的方法:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import qualified Data.Generics.Uniplate.Data as G
data Lit = S String | I Int deriving Data
data Expr = Sum Expr Expr | LitExpr Lit deriving Data
data Statement = Stmt [Expr] deriving Data
data AST = AST [Statement] deriving Data
strings :: AST -> [String]
strings a = [s | S s <- G.universeBi a]
進而:
*Main> strings (AST [Stmt [], Stmt [LitExpr (S "x"), Sum (LitExpr (I 5)) (LitExpr (S "y")), LitExpr (S "z")]])
["x","y","z"]
請注意,字串的定義實際上是單行的。所以,你只需要一行匯入,一行使用 uniplate 的universeBi函式提取所有文字,這就是運算式:
[s | S s <- G.universeBi ast]
這幾乎完全符合您的意圖:遍歷整個 AST,并找到出現在任何地方的所有文字字串。沒有比這更多的宣告了!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/363858.html
標籤:哈斯克尔
上一篇:當我的輸入值使用JavaScript日期選擇器更改時,如何呼叫事件?
下一篇:Haskell決議器分隔符
