Вопрос

Я ловлю себя на том, что пишу много кода, подобного

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

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

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

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

Это было полезно?

Решение

Вы можете разобрать код 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)|]

Другие советы

Шаблон шаблона Haskell не обеспечивает простых средств анализа произвольных струн, поэтому простейшее решение, вероятно, используется Cre Preprocessor.Однако встроенный в GHC не поддерживает строку, поэтому нам нужно пройти дополнительные параметры для использования «реального» вместо этого.
{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -pgmP cpp #-}

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

Вы можете использовать его так:

PRINT_EXP(foo (bar 1) (bar 2))
.

Есть пример генеракодицетагкодного кода Haskell с использованием GHC API здесь . .

Ой. Я думал, что это было бы легко, но насколько я могу сказать, это на самом деле невозможно .

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

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

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

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

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

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

{-# 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-Shell (часть NIX Package Manager ), вы даже можете быстро попробовать это«Одноклассник»:

$ 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"

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top