Domanda

Mi trovo a scrivere un sacco di codice come

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

Il problema è che il messaggio stampato può uscire dalla sincronizzazione con il codice effettivo eseguito.La soluzione ovvia è quella di generare automaticamente questo codice.

Un modo per farlo sarebbe quello di mettere tutto il testo in un file e scrivere un piccolo programma che legge il file e genera il codice sorgente Haskell da esso.Ma un'altra alternativa è usare il modello Haskell.

Qualcuno sò come vorrei scrivere una funzione che prende un String e genera il codice sopra da esso?Immagino che dovrebbe essere piuttosto facile, ma non è ben documentato.

È stato utile?

Soluzione

Puoi analizzare il codice Haskell usando il haskell-src-meta Pacchetto.Ecco un rapido esempio come si potrebbe combinare questo con il modello 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
.

E lo useresti come questo

{-# LANGUAGE QuasiQuotes #-}

[runShow|foo (bar 1) (bar 2)|]
.

Altri suggerimenti

Template Haskell non fornisce un mezzo semplice per analizzare stringhe arbitrarie, quindi la soluzione più semplice è probabilmente quella di utilizzare il preprocessore C.Tuttavia, quello incorporato in GHC non supporta la sezione delle righe, quindi abbiamo bisogno di superare opzioni aggiuntive per utilizzare invece il "vero".

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

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

Puoi quindi usarlo come questo:

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

C'è un esempio di codice Haskell di eval, utilizzando GHC API qui . .

Ahi. I pensò Questo sarebbe facile, ma per quanto posso dire, è in realtà impossibile .

Mi aspettavo che ci sia una funzione che trasforma una stringa in un'espressione, ma apparentemente non esiste una tale funzione. Non c'è nemmeno una funzione per caricare più codice sorgente dal disco. Quindi sembra che questo compito sia in realtà impossibile! Sono abbastanza sorpreso da quello.

La cosa più vicina che potrei fare è citare l'espressione che voglio correre, quindi costruire una giunzione che stampa piuttosto l'espressione quotata prima di eseguirla. Tuttavia, che mi mette alla misericordia della bella stampante di espressione di GHC. L'etichetta non viene fuori esattamente come ho digitato. (In particolare, sembra sostituire gli operatori con nomi completamente qualificati, che è solo doloroso.)

Avresti pensato che una caratteristica come questa sarebbe piuttosto banale da implementare. Il fatto che non sia implementato può quindi essere attribuito solo a una delle due cose:

    .
  1. nessuno ha effettivamente bisogno di questa funzione. (Beh, tranne me, ovviamente.)

  2. non è così banale come sembra. (Ad esempio, magari capitando quale contesto analizzare l'espressione in è irregolare in qualche modo?)

Puoi anche usare il Dump pacchetto che è stato scritto per gestire questo esatto caso:

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

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

foo = (+)
bar = (+1)
.

Quali stampe: (foo (bar 1) (bar 2)) = 5

Gestisce anche più di un'espressione separata da virgole:

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

Quali stampe: (foo (bar 1) (bar 2)) = 5 (map bar [1, 2]) = [2,3]

Bonus: Se hai installato Nix-shell (parte del Nix Package Manager ) Puoi anche provarlo rapidamente con questo"One-Liner":

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top