在Haskell中查找函数的行号

时间:2012-11-14 13:03:32

标签: haskell graphics compiler-construction pragma livecoding

我正在尝试创建一个Haskell程序,它将一些简单的2D形状绘制到屏幕上,但是当您将鼠标悬停在每个形状上时,它会打印创建形状的源代码行。

为了做到这一点,我希望能够创建带有尺寸参数的形状和表示行号的最终参数。像这样:

rect1 = Shape(Rectangle 2 2 lineNumber)

这将创建一个宽度为2像素,高度为2像素的矩形,并使用函数lineNumber来存储写入这段代码的行。 Haskell中是否存在这样的函数?创建一个很简单吗?

我搜索了堆栈溢出并找到了this question,其中回答者建议使用C ++中的__LINE__ pragma来实现类似的效果。这是最好的方法吗?还是有办法在纯Haskell中做到这一点?

2 个答案:

答案 0 :(得分:4)

你可以使用Template Haskell做到这一点,这在技术上是另一个GHC扩展,但可能比C预处理器更“纯粹”。

代码从here被盗并略有修改。

{-# LANGUAGE TemplateHaskell #-}

module WithLocation (withLocation) where
import Language.Haskell.TH

withLocation' :: String -> IO a -> IO a
withLocation' s f = do { putStrLn s ; f }

withLocation :: Q Exp
withLocation = withFileLine [| withLocation' |]

withFileLine :: Q Exp -> Q Exp
withFileLine f = do
    let loc = fileLine =<< location
    appE f loc

fileLine :: Loc -> Q Exp
fileLine loc = do
    let floc = formatLoc loc
    [| $(litE $ stringL floc) |]

formatLoc :: Loc -> String
formatLoc loc = let file = loc_filename loc
                    (line, col) = loc_start loc
                in concat [file, ":", show line, ":", show col]

像这样使用它(来自其他模块):

{-# LANGUAGE TemplateHaskell #-}

module Main where
import WithLocation

main = do
  $withLocation $ putStrLn "===oo0=Ü=0oo=== Kilroy was here"

答案 1 :(得分:1)

Pure Haskell不了解源代码级别的详细信息。最好的解决方案仍然是使用外部预处理器预处理haskell源文件以嵌入此信息,这是一种自然的关注点分离。

这样的特性对于像Lisp这样的动态编程系统更有意义,其中代码处理和执行阶段在时间上交错。但AFAIK甚至Common Lisp都没有这样的功能,而EmacsLisp却有(因为它的应用程序域是文本编辑器,不是因为它的创建者已经决定了)。