Why does this Haskell pattern work?

Consider this code:

  magic :: String -> Q Exp
 magic s = [e |  putStrLn s |]

Now, as far as I can tell, this should not work. Inside the Oxford brackets s missing. And yet, all this, apparently, works great.

If we change this example a little, it now breaks terribly:

  magic :: Exp -> Q Exp
 magic (VarE n) = [e |  putStrLn (nameBase n) |]

As before, we have a variable that does not matter. And this time it breaks. But he does not complain about a variable that is not within the scope; instead, he whines about some undocumented class devoid of an instance.

Does anyone know what is going on?

+4
source share
2 answers

s is within the brackets of Oxford. Basically, you are allowed to use values ​​of several types - those with Lift instances - inside the quoted expression, and they will automatically be turned into the corresponding code to recreate the corresponding value on the other end.

For example, a Lift instance for Integer s just creates the corresponding integer literal, and an instance for Maybe just creates the corresponding constructor applications. You can even define your own instances of Lift .

You get an “no instance” error, because n is a Name that Lift is not capable of.

+12
source

I think the short answer is that the magic function is expected to work, since the quotation brackets really fix their local variables (in a sense). Essentially, local compile-time variables in square brackets are replaced by their literal values ​​and become run-time constants. This is achieved by secretly invoking the elevator function, so that [| .. var .. |] becomes [| $ (lift var) |].

Perhaps you are confusing this behavior with the fact that they fix local variables uniquely, so that repeated calls to the same quote will not interfere with other variable names. This is achieved by calling newName behind the scenes, which provides unique variable names.

If this helps, I personally think of quotation brackets as “splicing generators” - small pieces of Haskell code that will be converted to AST at compile time and therefore become splines ready to be included anywhere. As indicated in Bulat's manuals ( links from ), they act as a form of macro preprocessor, as they are a mixture of Haskell functions that generate code and a simple automatic conversion of haskell code to TH AST.

Edit: It seems that I beat me to the answer - I leave my answer if it gives additional value.

+2
source

Source: https://habr.com/ru/post/1400056/


All Articles