Я пытаюсь извлечь STG-представление источника Haskell как String через Outputable, но похоже, что coreToStgArgs запаниковал следующим дампом:

user@machine ~/Desktop/hue $ runhaskell test.hs 
[foo :: forall a. Num a => a -> a
 [GblId, Arity=2, Caf=NoCafRefs, Str=DmdType] =
     \r srt:SRT:[] [$dNum a1] + $dNum a1 a1;,
 bar :: Int -> Int
 [GblId,test.hs: test.hs: panic! (the 'impossible' happened)
  (GHC version 7.10.3 for x86_64-unknown-linux):
    coreToStgArgs I# 3

Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

Вот файл FooBar.hs, который я хочу извлечь:

module FooBar where

foo a = a + a

bar :: Int -> Int
bar b = b + 3

Вот источник test.hs, который я использовал:

import CoreToStg
import GHC
import GHC.Paths
import Outputable
import StgSyn

mkDynFlags :: IO DynFlags
mkDynFlags = runGhc (Just libdir) getSessionDynFlags

mkSTG :: FilePath -> FilePath -> IO [StgBinding]
mkSTG proj src = do
    dflags  <- mkDynFlags
    ghc_core <- runGhc (Just libdir) $ do
        setSessionDynFlags (dflags {importPaths = [proj]})
        compileToCoreSimplified src
        -- compileToCoreModule src
    coreToStg dflags (cm_module ghc_core) (cm_binds ghc_core)

mkIOStr :: (Outputable a) => a -> IO String
mkIOStr obj = do
    dflags <- mkDynFlags
    let ppr_str = showPpr dflags obj
    return ppr_str

main :: IO ()
main = do
    let proj = "/home/user/Desktop/hue"
    let src  = proj ++ "/FooBar.hs"
    res <- mkIOStr =<< mkSTG proj src
    putStrLn res

Похоже, что кто-то за несколько лет до меня столкнулся с похожей проблемой:

https://ghc.haskell.org/trac/ghc/ticket/7159

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

РЕДАКТИРОВАТЬ: Перевод STG выглядит успешным для следующей программы, в которой bar b = b + 3 заменено на bar b = 3:

module FooBar where

foo a = a + a

bar :: Int -> Int
bar b = 3

Фактически, на первый взгляд кажется, что все работает, если индуцированный Core Haskell не заставляет выполнять примитивные операции. Например, bar b = 3 + 9 не работает.

6
Anton Xue 24 Июн 2017 в 12:34
1
Ошибка, с которой вы связались, говорит: « В конце концов, это не ошибка. Мне нужно было использовать CorePrep.corePrepPgm, прежде чем пытаться использовать CoreToStg.coreToStg. ».
 – 
melpomene
24 Июн 2017 в 15:38
Ах, после некоторой борьбы работает :) Спасибо!
 – 
Anton Xue
24 Июн 2017 в 16:23
Вы должны опубликовать рабочий код в качестве ответа.
 – 
melpomene
24 Июн 2017 в 16:36

1 ответ

Лучший ответ

Большое спасибо melpomene за указание на то, что я пропустил в документации.

Вот модифицированный исходный код test.hs, который работает:

import CorePrep
import CoreToStg
import GHC
import GHC.Paths
import GhcMonad
import HscTypes
import Outputable
import StgSyn
import System.IO

mkSTG :: FilePath -> FilePath -> IO [StgBinding]
mkSTG proj src = runGhc (Just libdir) $ do
        env    <- getSession
        dflags <- getSessionDynFlags
        setSessionDynFlags (dflags {importPaths = [proj]})
        target <- guessTarget src Nothing
        setTargets [target]
        load LoadAllTargets

        mod_graph <- getModuleGraph
        let mod_sum = head mod_graph  -- This is bad practice
        pmod <- parseModule mod_sum
        tmod <- typecheckModule pmod
        dmod <- desugarModule tmod
        let guts  = coreModule dmod
        let loc   = ms_location mod_sum
        let binds = mg_binds guts
        let tcs   = mg_tcs guts
        prep <- liftIO $ corePrepPgm env loc binds tcs
        liftIO $ coreToStg dflags (mg_module guts) prep

mkIOStr :: (Outputable a) => a -> IO String
mkIOStr obj = do
    dflags <- runGhc (Just libdir) getSessionDynFlags
    let ppr_str = showPpr dflags obj
    return ppr_str

main :: IO ()
main = do
    let proj = "/home/celery/Desktop/hue"
    let src  = proj ++ "/FooBar.hs"
    res <- mkIOStr =<< mkSTG proj src
    putStrLn res

Я не уверен, как лучше всего восстановить ModSummary (и, следовательно, ModuleName) из Target, но я смутно помню, что это был первый элемент ModuleGraph, который определяется как type ModuleGraph = [ModSummary].

Сигнатура типа для corePrepPgm также различается между GHC 7 и 8:

https://downloads.haskell.org/~ghc/7.10.1/docs/html/libraries/ghc-7.10.1/CorePrep.html

https://downloads.haskell.org/~ghc/latest/docs/html/libraries/ghc-8.0.1/CorePrep.html

Предложения по улучшению приветствуются :)

РЕДАКТИРОВАТЬ : я нашел примеры встречных примеров - head ModuleGraph не всегда является целью. Мой текущий обходной путь - проверить, содержит ли какой-либо ModSummary в ModuleGraph местоположение, которое совпадает с местоположением исходного исходного файла.

1
Anton Xue 10 Фев 2018 в 22:24
«- Это плохая практика» - действительно, но API GHC наполнен историческими случайностями (например, представление непустого списка с типом []), которые иногда в основном вынуждают вас делать «плохие» вещи. Так что не расстраивайтесь по этому поводу!
 – 
user2407038
24 Июн 2017 в 17:55