You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TemplateHaskell实现编译期生成Narration结构?避免重复解析

Solution to Avoid Duplicate Parsing in Template Haskell Embedding

Great question! The core issue here is that your current code validates the narration file at compile time but still generates code that parses it again at runtime. To fix this, we can directly embed the compiled-time parsed Narration value into the generated Haskell AST, so runtime uses it directly without re-parsing.

Here's how to do it step by step:


1. Ensure Your Narration Type Has a Lift Instance

Template Haskell needs a Lift instance to convert runtime values (in this case, your compiled-time Narration value) into Haskell expression ASTs. The easiest way is to derive it with the DeriveLift extension:

{-# LANGUAGE DeriveLift #-}

-- Your existing Narration definition
data Narration = Narration { ... } -- Replace with your actual constructors and fields
  deriving (Lift) -- Add this to derive the Lift instance automatically

If you can't derive it (e.g., for types without default Lift support), you can write a manual instance:

import Language.Haskell.TH.Lift

instance Lift Narration where
  lift (YourNarrationCtor str num nestedItems) = 
    [| YourNarrationCtor $(lift str) $(lift num) $(lift nestedItems) |]
  -- Repeat this pattern for all your Narration constructors

2. Rewrite embedNarration to Embed the Parsed Value Directly

Instead of generating code that calls parseNarration at runtime, we'll parse the file at compile time, validate it, then convert the resulting Narration value directly into an AST expression:

import Language.Haskell.TH
import Language.Haskell.TH.Lift
import System.IO (readFile)

embedNarration :: String -> Q Exp
embedNarration file = do
  -- Use runIO instead of unsafePerformIO: it's the safe, idiomatic way for IO in TH
  text <- runIO $ readFile file
  case parseNarration text of
    Left err -> 
      throw $ ErrorCall $ "Compile-time parsing failed for " ++ file ++ ": " ++ err
    Right parsedNarration -> 
      lift parsedNarration -- Convert the validated Narration value to an AST expression

How This Works

  • Compile Time: When you use $(embedNarration "path/to/narration.txt") in your code, Template Haskell will:

    1. Read the target file and parse it into a Narration value.
    2. If parsing fails, throw a clear compile-time error (matching your original validation behavior).
    3. If successful, convert the Narration value into a concrete Haskell expression (e.g., Narration "Chapter 1" [Paragraph "Welcome to the story"]).
  • Runtime: The generated code will directly use this pre-parsed Narration value—no more calls to parseNarration, no duplicated work, and zero runtime parsing overhead.


Why This Beats Your Original Code

Your original code generated something like:

(fromRight undefined . parseNarration) "entire file content here"

Which forces redundant runtime parsing even though you already validated the file at compile time. The rewritten version skips runtime parsing entirely by embedding the final Narration structure directly into your code.

内容的提问来源于stack exchange,提问作者Eva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:00:47