6 Stimmen

Lift-Instanz für eine Funktion?

Ich muss eine Funktion in Template-Haskell-Code einfügen. Ich verwende die Ausdruckssyntax:

\[|f|\]Einige Funktionen scheinen automatisch zu funktionieren. Für diese spezielle Funktion erhalte ich jedoch die folgende Fehlermeldung:

   No instance for (Lift (String -> \[Content\]))

Ich habe keine Ahnung, wie ich eine Aufzugsinstanz für eine Funktion erstellen kann, und kann anscheinend keine nützlichen Informationen finden. Kann mir jemand eine Quelle nennen oder mir eine Vorstellung davon geben, wie dies im Allgemeinen erreicht wird? In der Zwischenzeit werde ich sehen, ob ich mein spezifisches Beispiel eingrenzen kann.

8voto

intoverflow Punkte 991

Ich werde einen Versuch wagen, aber TH kann schwer zu debuggen sein, ohne mehr Code zu sehen.

Werfen wir einen Blick auf einen Beispielcode:

foo.hs:

{-# Language TemplateHaskell #-}

baz x = let f y = x + y
    in [| f |]

bez x = let f y = x + y
    in [| \y -> f y |]

boz x = [| \y -> x + y |]

g x y = x + y

byz x = [| g x |]

Jetzt können wir dies in GHCi starten (ich verwende Version 7.0.2, die mit der aktuellen Haskell-Plattform ausgeliefert wird):

$ ghci foo.hs -XTemplateHaskell
*Main> :m +Language.Haskell.TH
*Main Language.Haskell.TH> runQ (baz 2)

<interactive>:1:7:
No instance for (Language.Haskell.TH.Syntax.Lift (a0 -> a0))
  arising from a use of `baz'
Possible fix:
  add an instance declaration for
  (Language.Haskell.TH.Syntax.Lift (a0 -> a0))
In the first argument of `runQ', namely `(baz 2)'
In the expression: runQ (baz 2)
In an equation for `it': it = runQ (baz 2)
*Main Language.Haskell.TH> runQ (bez 2)

<interactive>:1:7:
    No instance for (Language.Haskell.TH.Syntax.Lift (a0 -> a0))
      arising from a use of `bez'
    Possible fix:
      add an instance declaration for
      (Language.Haskell.TH.Syntax.Lift (a0 -> a0))
    In the first argument of `runQ', namely `(bez 2)'
    In the expression: runQ (bez 2)
    In an equation for `it': it = runQ (bez 2)
*Main Language.Haskell.TH> runQ (boz 2)
LamE [VarP y_0] (InfixE (Just (LitE (IntegerL 2))) (VarE GHC.Num.+) (Just (VarE y_0)))
*Main Language.Haskell.TH> runQ (byz 2)
AppE (VarE Main.g) (LitE (IntegerL 2))

Was ich hier getan habe, ist der Versuch, die runQ um zu sehen, wie der TH-Spleiß für jede meiner Funktionen im Beispielcode aussieht. Es schlägt fehl bei baz y bez , sondern funktioniert für boz y byz .

Betrachtet man die TH für boz y byz können wir sehen, wie Funktionen angehoben werden: boz ist im Grunde nur ein Verweis auf + mit Namen (in VarE GHC.Num.+ ), während byz bezieht sich nur auf g mit Namen (in VarE Main.g ).

Para baz y bez steht diese Option nicht zur Verfügung: Beide Funktionen versuchen, die f die lokal gebunden ist; daher ist der Verweis auf VarE f würde keinen Sinn machen außerhalb von baz y bez .

Was soll ein Entwickler also tun? Kurz gesagt: Anstatt zu versuchen [| f |] müssen Sie den Ausdruck für f im Aufzug direkt in Form von Identifikatoren, die dort gebunden werden, wo der Spleiß auftritt.

Nebenbei bemerkt, ist es sehr einfach zu schreiben Lift Instanzen für algebraische Datentypen, da Sie global definierte Funktionen immer aufheben können. Hier ist eine für Maybe :

instance Lift a => Lift (Maybe a) where
  lift Nothing = [| Nothing |]
  lift (Just a) = [| Just a |]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X