2015-07-14 15 views
18

Próbuję dowiedzieć się trochę Template Haskell i quasi cytat, i szukam funkcji, które odbywają się String i analizuje je Q Exp, więc typ to:Szablon Haskell: Czy istnieje funkcja (lub specjalna składnia), która analizuje łańcuch i zwraca Q Exp?

String -> Q Exp 

Próbowałem szukając hoogle, ale wyniki, które widziałem, miały związek z podniesieniem literałów String do Q Exp, a najbliżej znalazłem Language.Haskell.TH.dyn, który robi to, co chcę, ale tylko dla jednej zmiennej.

Czy są jeszcze inne opcje? Na przykład. specjalna składnia? Właśnie zapoznałem się z [||] i $(), więc może jest coś dla tego celu?

Przykładem tego, jak mogę sobie wyobrazić, że to działa:

runQ (parse "(1+)") == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing 

Również jestem świadomy tego

runQ [| (1+) |] == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing 

ale to przyzwyczajenie praca ze zmiennymi ciągów ponieważ - ze zrozumiałych względów - ciąg wewnątrz jest traktowane jako dosłowne.

runQ [| "(1+)" |] == LitE (StringL "(1+)") 

Edit (25.07.2015): zacząłem używając haskell-src-meta, i wydaje się działać dobrze do tej pory. Jednak zajmuje to trochę czasu cabal install (około 10 minut na moim komputerze). Szkoda, że ​​mój pakiet jest w rzeczywistości raczej mały i chciałbym, aby instalacja była szybka. Ktoś wie o rozwiązaniu, które ma mniejsze zależności?

+3

Wierzę, że [haskell-src-meta] (https://hackage.haskell.org/package/haskell-src-meta) zapewnia to – luqui

+2

@luqui Jestem nieco zdezorientowany tym pakietem. W opisie jest napisane, że coś jest "jeszcze nie w 100%". Czy ta funkcja nie powinna już istnieć w GHC? Musi tak być, ponieważ zajmuje '[| | 1+) |] i jest całkowicie zdolny do przekształcenia go w' (InfixE _) '. Dlaczego więc istnieje zapotrzebowanie na pakiet stron trzecich, który może, ale nie musi, być przetwarzany poprawnie? Czy też błędnie interpretuję i to jest kod kanoniczny, którego używa GHC? Czy GHC po prostu nie ujawnia tej funkcji? Byłbym wdzięczny za jasność w tej sprawie. :) – Wizek

+1

AFAIU GHC nie ujawnia tego kodu, ale nie jestem ekspertem TH – luqui

Odpowiedz

2

Jak każdy już powiedział haskell-src-meta zapewnia

parsePat :: String -> Either String Pat 
parseExp :: String -> Either String Exp 
parseType :: String -> Either String Type 
parseDecs :: String -> Either String [Dec] 

gdzie Pat, Exp, Type i Dec są takie same jak z Language.Haskell.TH.Syntax.


Dlaczego nie GHC narażać własnego parsera?

To robi. Uruchomienie GHCi z ghci -package ghc (ghc jest domyślnie ukrytym pakietem) i możesz zaimportować Parser. Ma funkcje do analizy String na wstępne AST (których deklaracje danych są w HsSyn) dla wzorów, wyrażeń, typów i deklaracji.

OK, to dlaczego nie istnieją biblioteki, który używa tego parsera i przekształca swoje wyjście być AST od template-haskell (jednego w Language.Haskell.TH.Syntax)?

Patrząc wewnątrz HsSyn, jego oczywiste, że AST nie jest zupełnie taka sama jak w Language.Haskell.TH.Syntax. Otwórz oba: HsExpr i Exp, a obok siebie zobaczysz, że ten ostatni jest wypełniony typami takimi jak PostTc id <some-other-type> i PostRn id <some-other-type>. Kiedy AST jest przekazywana z parsera do renamera do sprawdzania typu, te bity i części powoli się wypełniają.Na przykład, nie znamy nawet fiksacji operatorów, dopóki nie przejdziemy do sprawdzania typów!

Aby uzyskać pożądane funkcje, musielibyśmy uruchomić o wiele więcej niż tylko analizator składni (przynajmniej rewizor i sprawdzanie typu również, być może więcej). Wyobraź sobie, że: za każdym razem, gdy chcesz przeanalizować nawet małe wyrażenie, takie jak "1 + 2", musisz jeszcze sprawdzić typ importu. Nawet wtedy, konwersja z powrotem do Language.Haskell.TH.Syntax nie byłaby spacerkiem w parku: GHC ma wiele osobliwości, takich jak własny specjalny globalny sposób przechowywania nazw i identyfikatorów.

Hmmm ... ale co robi GHC z quasi-cytatami?

To jest fajna część! W przeciwieństwie do Exp, HsExpr ma HsSplice do reprezentowania splotów. Spójrz na typy, dla pierwszych dwóch konstruktorów:

HsTypedSplice :: id -> LHsExpr id -> HsSplice id. -- things like [|| 1 + 2 ||] 
HsUntypedSplice :: id -> LHsExpr id -> HsSplice id -- things like [| 1 + 2 |] 

Zauważ, że nie są one przechowywanie String, są już przechowywania AST! Splices są analizowane w tym samym czasie co reszta AST. I podobnie jak w pozostałej części AST spawy będą przejdzie wraz z renamer, typ sprawdzania itp gdzie brakujące dane zostaną wypełnione.

Więc jest to całkowicie niemożliwe, aby użyć parsera GHC za

Prawdopodobnie nie. Ale wyrzucenie go z reszty GHC może być dość trudne. Jeśli chcesz użyć parsera GHC, musimy również uruchomić sprawdzanie typu i zmianę nazwy, może być bardziej elegancko i prostiej po prostu użyć niezależnego analizatora składni, takiego jak haskell-src-exts (czyli od tego zależy Haskell-src-meta), który jest w stanie zrobić wszystko w jednym przebiegu (Fixions, na przykład, są jedną z rzeczy, które musisz dać przed czasem do tego parsera).

+1

Dlaczego utrwalanie nie byłoby znane do momentu sprawdzenia typu? Czy to nie jest pojęciowo warstwa nad parserem, aby stworzyć bardziej kompletną AST? Dlaczego przed tym wydarzeniem miałyby się zdarzyć fantazyjne rzeczy? – dfeuer

+0

@dfeuer Mity są wypełniane podczas fazy zmiany nazwy (co następuje tuż przed sprawdzeniem typu), więc sprawdzanie typu jest pierwszą fazą, w której fiksacje są w pełni obecne. Prawdopodobnie nie rozumiem twojego pytania ... – Alec

+0

Myślałem, że renamer był związany ze sprawdzeniem typu; może to było złe. – dfeuer

Powiązane problemy