2012-07-20 31 views
4

在一個非常簡單的道理,我有類似如下:一個AST的表達式quasiquoter,其中一個構造函數產生一次性計算?

type Runtime a = {- More or less a StateT on top of an Either monad -} 

-- The list of strings in Fn is a bunch of parameter names, the values of 
-- which are pushed into the state of the runtime before executing the actual 
-- function expr 
data Expr = Num Int 
      | Str T.Text 
      | Fn [T.Text] (Runtime Expr) 
      | {- Bunch of other constructors -} 

eval :: Expr -> Runtime Expr 
parseExp :: Parser Expr 

現在,我從來沒有用過的模板哈斯克爾任何東西之前,我決定還是想方便的準報價者爲我的玩具語言,所以我承認我可能會錯過某些明顯的東西。

但無論如何,我開始擺弄一下它,跟着一些教程等,基本上發現除了如何處理Fn構造函數之外,其他所有東西都很容易。

在網絡上我的信息foragings,我發現了兩個普通的方式讓人們寫下了表達報價者:

  • 使他們Expr數據類型TH的實例:■Lift和簡單[|報價|]認爲解析導致
  • 推導DataTypeable他們相當於Expr,然後在相同的解析器結果

在這兩種情況下均適用dataToExpQ表達,我遇到了與Runtime Expr併發症。對於第一種情況,問題是,我無法弄清楚如何實現:

instance Lift Expr where 
    lift (Fn ps e) = [| Fn ps ...? |] 

(我沒有管理實施Data.Text實例我自己雖然)。

我想real的問題是我根本不知道TH還不夠好,但迄今爲止沒有足夠的教程或exmaples幫助我得到這個地方的任何地方。

在第二種情況下,這個問題是,對Expr是的Data一個實例,也需要有一個

instance Data (StateT (...) (Either ...) Expr) where 
    -- Something 

我的問題則是,是否有一個簡單的方法來做到這一點?或者我應該重新思考我的玩具語言的功能是如何工作的?

如果是後者,有關如何獲得等效功能而不在monad中運行它們的任何建議?畢竟,這似乎是直觀的解決方案,因爲該語言的運行環境需要狀態和錯誤處理(這是我使用的Either)。

+0

請您詳細說明您遇到的問題。 – dave4420 2012-07-20 09:25:55

+0

試圖澄清一點點的併發症。問題是,我幾乎不知道哪裏可以從任何一個實現開始,所以我不能詳細說明更多 - 這是迄今爲止我得到了多少。 – Kben 2012-07-20 09:50:25

回答

4

您的Expr數據類型不需要升級就可以爲其構建一個quasiquoter,在這種情況下,不可能實現Lift實例。原因是你不能「看」Runtime Expr值,因爲StateT值本質上是函數,並沒有通用的方法來找出函數的作用。

你需要做的是構建AST「手動」構建Expr,即不使用[| (或更具體地說,您可以使用[| |] - 引用來幫助您構建AST,但不能直接引用Expr數據)。

所以在本質上,你需要類型

parseExpQ :: Parser ExpQ 

的解析器產生代表建立Expr所需的Haskell代碼的Exp。對於Fn構造函數,您需要使用DoE構造函數或使用InfixE>>=的綁定鏈構建do-block。

如果這聽起來太複雜了,您的另一種選擇是將函數體表示爲表達式(或語句列表,取決於您的玩具語言的語義)。即

data Expr = Num Int 
      | Str T.Text 
      | Fn [T.Text] [Statement] 

並定義Statement類型,以便它可以解釋爲生產出你以前使用StateT Either用於相同的效果。

+0

謝謝,我想我明白了。我碰到一個單獨的問題: 在ghci中,運行任何類似[玩具| someExpr |]會導致「解析輸入錯誤'|'''',儘管我已經設置它來處理TH(runQ [| whatever |按預期工作)。任何想法? – Kben 2012-07-20 14:50:06

+0

您需要'{ - #LANGUAGE QuasiQuotes# - }'在頂部或您的文件或-XQuasiQuotes作爲編譯器選項。 – shang 2012-07-20 14:58:56

+0

啊,對不起,我沒有注意到你說GHCi。在GHCi中,您可以通過以下方式啓用語言擴展:':set -XQuasiQuotes' – shang 2012-07-20 14:59:45

相關問題