Распечатать и выполнить строку - PullRequest
6 голосов
/ 29 февраля 2012

Я пишу много кода, например

putStr "foo (bar 1) (bar 2) ="
print $ foo (bar 1) (bar 2)

Беда в том, что напечатанное сообщение может не синхронизироваться с фактически выполненным кодом.Очевидное решение - автоматически сгенерировать этот код.

Один из способов сделать это - поместить весь текст в файл и написать небольшую программу, которая читает файл и генерирует из него исходный код на Haskell.Но другой альтернативой является использование Template Haskell.

Кто-нибудь знает, как я мог бы написать функцию, которая берет String и генерирует из нее приведенный выше код?Я предполагаю, что это должно быть довольно легко, но TH не очень хорошо задокументировано.

Ответы [ 5 ]

8 голосов
/ 29 февраля 2012

Вы можете проанализировать код на Haskell, используя пакет haskell-src-meta.Вот краткий пример того, как вы могли бы объединить это с шаблоном Haskell.

{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.Meta

runShow = QuasiQuoter
    { quoteExp  = runShowQQ
    , quotePat  = undefined
    , quoteType = undefined
    , quoteDec  = undefined
    }

runShowQQ :: String -> Q Exp
runShowQQ s = do
    let s'          = s ++ " = "
        Right exp = parseExp s
        printExp  = appE [|print|] (return exp)
    infixApp [|putStr s'|] [|(>>)|] printExp

И вы бы использовали его вот так

{-# LANGUAGE QuasiQuotes #-}

[runShow|foo (bar 1) (bar 2)|]
4 голосов
/ 29 февраля 2012

Шаблон Haskell не предоставляет простых средств синтаксического анализа произвольных строк, поэтому простейшим решением, вероятно, является использование препроцессора Си.Однако встроенный в GHC не поддерживает строковое форматирование, поэтому нам необходимо передать дополнительные параметры, чтобы использовать вместо него «настоящий».

{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -pgmP cpp #-}

#define PRINT_EXP(x) (putStr #x >> putStr " = " >> print (x))

Затем вы можете использовать его следующим образом:

PRINT_EXP(foo (bar 1) (bar 2))
1 голос
/ 29 февраля 2012

Существует пример eval -подобного кода на Haskell с использованием GHC API здесь .

0 голосов
/ 25 сентября 2016

Вы также можете использовать пакет dump , который был написан для обработки этого точного варианта использования:

{-# language QuasiQuotes #-}
import Debug.Dump

main = putStrLn [d| foo (bar 1) (bar 2) |]

foo = (+)
bar = (+1)

, который печатает: (foo (bar 1) (bar 2)) = 5

Это такжеобрабатывает несколько выражений, разделенных запятыми:

putStrLn [d| foo (bar 1) (bar 2), map bar [1, 2] |]

Что печатает: (foo (bar 1) (bar 2)) = 5 (map bar [1, 2]) = [2,3]

Бонус: если у вас установлена ​​nix-оболочка (часть менеджера пакетов nix ) Вы можете даже попробовать это быстро с этим «одним вкладышем»:

$ nix-shell -p "nix-shell -p "haskellPackages.ghcWithPackages (p: [p.dump])" --run "echo '{-# language QuasiQuotes #-}; import Debug.Dump; foo = (+); bar = (+1); main = putStrLn [d| foo (bar 1) (bar 2), map bar [1, 2] |]' | runhaskell"

0 голосов
/ 29 февраля 2012

Уч.Я подумал , что это будет легко, но, насколько я могу судить, на самом деле это невозможно .

Я ожидал, что будет функция, которая превращает строку ввыражение, но, видимо, такой функции не существует.Нет даже функции для загрузки большего количества исходного кода с диска.Так что, похоже, эта задача на самом деле невозможна!Я очень удивлен этим.

Самое близкое, что я мог сделать, это заключить в кавычки выражение, которое я хочу запустить, и затем создать соединение, которое красиво печатает выражение в кавычках перед его выполнением.Тем не менее, это ставит меня в зависимость от симпатичного принтера GHC.Ярлык не выходит точно , как я его напечатал.(В частности, кажется, что операторы заменяются полностью определенными именами, что просто болезненно.)

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

  1. Никто на самом деле не нуждается в этой функции.(Ну, кроме меня, очевидно.)

  2. Это не так тривиально, как кажется.(Например, может быть, как-то сложно понять, в каком контексте разбирать выражение?)

...