Нахождение номера строки функции в Haskell

Я пытаюсь создать программу на Haskell, которая рисует некоторые простые 2d фигуры на экране, но когда вы наводите курсор мыши на каждую фигуру, она печатает строку исходного кода, где фигура была создана.

Чтобы сделать это, я хотел бы иметь возможность создавать фигуры с параметрами для их размеров и конечным параметром, который указывает номер строки. Что-то вроде этого:

rect1 = Shape(Rectangle 2 2 lineNumber)

Это создаст прямоугольник шириной 2 пикселя, высотой 2 пикселя и использует функцию lineNumber для хранения строки, на которой был написан этот фрагмент кода. Существует ли такая функция в Haskell? Это просто создать?

Я искал переполнение стека и нашел этот вопрос, где ответчик предполагает, что прагма __LINE__ из C++ может быть использована для достижения аналогичного эффекта. Это лучший способ сделать это или есть способ сделать это на чистом Хаскеле?

2 ответа

Решение

Вы можете сделать это с помощью Template Haskell, который технически является еще одним расширением GHC, но, вероятно, чем-то более "чистым", чем препроцессор Си.

Код украден отсюда и слегка изменен.

{-# 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"

Чистый Haskell не знает о деталях уровня исходного кода. Лучшим решением по-прежнему является предварительная обработка исходного файла haskell с помощью внешнего препроцессора для встраивания этой информации, это естественное разделение проблем.

Такая возможность гораздо более значима для систем динамического программирования, таких как Lisp, где этапы обработки и выполнения кода чередуются во времени. Но у AFAIK даже Common Lisp такой функции нет, а у EmacsLisp (только потому, что домен приложения является текстовым редактором, а не потому, что его создатели так решили).

Другие вопросы по тегам