Open jwiegley opened 7 years ago
This is really just: findBinding (StaticKey "a") (parseNixString "inherit a b c;")
. Where a quasi-quater would be become interesting is in anti-quoting Haskell variables correctly based on their type.
The basic quasi-quoter is in place now, just import Nix.TH
, turn on QuasiQuotes
and TemplateHaskell
, and then use [nix| 2 + 3|]
, which will parse that text into a value of type NExpr
, exactly as parseNixString
would.
There are a few next steps for this work to make it more useful:
[x] In Nix.TH
, write an evaluation pass to determine the free variables in a Nix expression, so they can be bound to Haskell variables of type NExpr
within scope. For example: foo x = [nix| x + 1 |]
.
[x] Using ToNix
, allow anti-quoting arbitrary Haskell expressions which are then rendered into their NExpr
equivalents before interpolation. Then we could do: [nix| 1 + $((100**2))|]
. A syntax for this type of anti-quotation needs to be determined, and a constructor added to NExprF
to hold the String
representing the Haskell expression to be evaluated.
[ ] Allow Haskell functions to be anti-quoted, so that you could do: [nix| $((head)) [1 2|]
.
[ ] Allow Nix functions to be evaluated into native Haskell functions. Thus, we could do this: `let f = nixFunction "my-function.nix" in [nix| $((f 1)) + 2|]. The intention here is to make the transition between Haskell and Nix entirely seamless, while preserving lazy semantics as closely as possible to the expectations of both languages.
We now support capturing of Haskell bindings, and Nix expression patterns:
foo :: ToExpr a -> a -> NExprLoc
foo x = [nix| x + 100|]
bar :: NExprLoc -> NExprLoc
bar [nix| x + 200 |] = x
What it the state of Nix.TH? I am having trouble using it. The error I keep getting is:
[nix-shell:~/iohk/nix-tools]$ ghci -package hnix -XQuasiQuotes -XTemplateHaskell
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Prelude> import Nix.TH
Prelude Nix.TH> [nix| x |]
<interactive>:2:6: error:
• Can't find interface-file declaration for variable Data.Text.Internal.pack
Probable cause: bug in .hi-boot file, or inconsistent .hi file
Use -ddump-if-trace to get an idea of which file caused the error
• In the first argument of ‘Nix.Expr.Types.NSym’, namely
‘(Data.Text.Internal.pack (((:) 'x') []))’
In the first argument of ‘Data.Fix.Fix’, namely
‘(Nix.Expr.Types.NSym (Data.Text.Internal.pack (((:) 'x') [])))’
In the expression:
(Data.Fix.Fix
(Nix.Expr.Types.NSym (Data.Text.Internal.pack (((:) 'x') []))))
Sounds like a bug that will need further examination.
What's the status of the bug?
I can reproduce the bug in cabal repl
on Linux. https://gitlab.haskell.org/ghc/ghc/issues/12596 looks similar.
Somewhat related to:
Allow Nix functions to be evaluated into native Haskell functions. Thus, we could do this: `let f = nixFunction "my-function.nix" in [nix| $((f 1)) + 2|]. The intention here is to make the transition between Haskell and Nix entirely seamless, while preserving lazy semantics as closely as possible to the expectations of both languages.
In Conversion
there is now inHask*
(best name I came up so far for) methods, methods are isomorphisms between simple Haskell (which for simplicity I call Hask category) & embedded into it Nix category. It is not total isomorphism, meaning it is isomorphism transformatons that currently work on particular types.
A lot of Conversion
module is really an isomorphism that can be denoted & leveraged through more default Haskell means of defining isomorphisms. inHask*
functions is Nix -> computation in Haskell -> Nix. What is asked in the head post is a Nix function application inside Haskell, automatic Nix function -> Haskell function transformation. Currently it seems too early, since it would blur the line between Haskell & Nix & can complicate further work on the project code, when Haskell pathing suddenly dissapers inside .nix
. We also probably need a solid language symantic checer & type checker to load .nix
files, that is why it seems that it needs to be done at a pretty late stage when the HNix code would be solid & clear enough to withstand that blurring (it is just my current view on it).
https://github.com/haskell-nix/hnix/issues/52#issuecomment-492074339 <- now works
Cleaning up the thread accordingly.
Main quasiquoter mode works, and updated the type system, so it looks fancier:
-- add QuasiQuotes & TemplateHaskell into scope
λ> [nix| { a }: let v = "now"; in rec { fancy = ''Hey, ${v}!''; ver = builtins.languageVersion; } |]
Fix (NAbs (ParamSet Nothing Closed [(VarName "a",Nothing)]) (Fix (NLet [NamedVar (StaticKey (VarName "v") :| []) (Fix (NStr (DoubleQuoted [Plain "now"]))) (SourcePos {sourceName = "<string>", sourceLine = Pos 1, sourceColumn = Pos 13})] (Fix (NSet Recursive [NamedVar (StaticKey (VarName "fancy") :| []) (Fix (NStr (Indented 0 [Plain "Hey, ",Antiquoted (Fix (NSym (VarName "v"))),Plain "!"]))) (SourcePos {sourceName = "<string>", sourceLine = Pos 1, sourceColumn = Pos 33}),NamedVar (StaticKey (VarName "ver") :| []) (Fix (NSelect Nothing (Fix (NSym (VarName "builtins"))) (StaticKey (VarName "languageVersion") :| []))) (SourcePos {sourceName = "<string>", sourceLine = Pos 1, sourceColumn = Pos 57})])))))
Allow Haskell functions to be anti-quoted
Useful bits for this is in: https://github.com/mikeplus64/QuasiText/blob/master/src/Text/QuasiText.hs (as $( )
).
Quasiquoter pattern matching got broken during migration to Text
. I was checking the main way, but not checked the pattern match way. Pattern match tries to launch pack
and searches for it in the wrong module (pack
is in Data.Text
):
λ> bar [nix| x + 200 |] = x
<interactive>:13:5: error:
• Exception when trying to run compile-time code:
Can't construct a pattern from name Data.Text.Internal.pack
CallStack (from HasCallStack):
error, called at libraries/template-haskell/Language/Haskell/TH/Syntax.hs:1300:22 in template-haskell:Language.Haskell.TH.Syntax
Code: Language.Haskell.TH.Quote.quotePat nix " x + 200 "
• In the quasi-quotation: [nix| x + 200 |]
GHC upstream: https://gitlab.haskell.org/ghc/ghc/-/issues/12596
Workaround: https://stackoverflow.com/questions/38143464/cant-find-inerface-file-declaration-for-variable - but that needs to be ported to PatQ
& so far I have not found how to do it (I am currently not well-versed in TemplateHaskell metaprogramming dimension).
The support for free variables appears to not be working in hnix-0.14.0.5
, unless I'm doing something wrong:
>>> x = mkInt 1
>>> [nix|x|]
Fix (NSym "x")
I also tested in a standalone file outside of the REPL, too, with the same result.
Currently main HNix branch does:
λ> x = mkInt 1
x :: Nix.Expr.Types.NExpr
λ> [nix|x|]
Fix (NSym (VarName "x"))
Which is a step in the right direction.
You are right, the test should be there all along.
Gabriella, I am sorry, it is probable that it is me who broke this feature.
Can you detail the reason/priority of use, so I can infer things?
As I still have difficulty in metaprogramming on the TH level- it probably would be a task that at least take a chunk of time of learning & troubleshooting this.
Not a high priority for us
Thank you. But I would know I need to address it, as I am probably who broke it.
P.S.
Overall, the undocumented breakages in Nix release 2.3.15 & 2.4 & 2.5 put me & the project in a hard place. That upstream breaks without notification/documentation were addressed by public action in upstream by maintainers, but that does not resolves the situation really.
The basic quasi-quoter is in place now, just import
Nix.TH
, turn onQuasiQuotes
andTemplateHaskell
, and then use[nix| 2 + 3|]
, which will parse that text into a value of typeNExpr
, exactly asparseNixString
would.There are a few next steps for this work to make it more useful:
[ ] In
Nix.TH
, write an evaluation pass to determine the free variables in a Nix expression, so they can be bound to Haskell variables of typeNExpr
within scope. For example:foo x = [nix| x + 1 |]
.[x] Using
ToNix
, allow anti-quoting arbitrary Haskell expressions which are then rendered into theirNExpr
equivalents before interpolation. Then we could do:[nix| 1 + $((100**2))|]
. A syntax for this type of anti-quotation needs to be determined, and a constructor added toNExprF
to hold theString
representing the Haskell expression to be evaluated.[ ] Allow Haskell functions to be anti-quoted, so that you could do:
[nix| $((head)) [1 2|]
.[ ] Allow Nix functions to be evaluated into native Haskell functions. Thus, we could do this: `let f = nixFunction "my-function.nix" in [nix| $((f 1)) + 2|]. The intention here is to make the transition between Haskell and Nix entirely seamless, while preserving lazy semantics as closely as possible to the expectations of both languages.