Zulip Chat Archive

Stream: lean4

Topic: proj to app


Leni Aniva (Nov 30 2023 at 01:15):

Is there a function that can convert Expr.proj to the equivalent Expr.app?

For example .proj Prod 0 x is x.0, and I want to transform it to the equivalent Prod.fst x`

The documentation says

When exporting Lean developments to other systems, proj can be replaced with typeName.rec
applications.
but how can this be done since Prod.rec relies on the motive?

Kyle Miller (Nov 30 2023 at 02:10):

I think you use docs#Lean.getStructureFields to get the field names, and then use docs#Lean.getFieldInfo? to get a structure that contains the projFn field.

It looks like there's docs#Lean.Meta.mkProjection, to create the Expr.app. It can also handle field names that are subfields (fields from a structure it extends)

Leni Aniva (Nov 30 2023 at 07:18):

Kyle Miller said:

I think you use docs#Lean.getStructureFields to get the field names, and then use docs#Lean.getFieldInfo? to get a structure that contains the projFn field.

It looks like there's docs#Lean.Meta.mkProjection, to create the Expr.app. It can also handle field names that are subfields (fields from a structure it extends)

is there a way to get the list of all structures for this?

Notification Bot (Dec 04 2023 at 23:31):

Leni Aniva has marked this topic as resolved.

Leni Aniva (Dec 06 2023 at 04:59):

Kyle Miller said:

I think you use docs#Lean.getStructureFields to get the field names, and then use docs#Lean.getFieldInfo? to get a structure that contains the projFn field.

It looks like there's docs#Lean.Meta.mkProjection, to create the Expr.app. It can also handle field names that are subfields (fields from a structure it extends)

I tried using this function and I found this symbol that causes it to crash: ULift.down. The value of this function is fun α self => self.1, which seems to be ok on the surface. However when I invoke Meta.mkProjection on the operand self.1, I get

unexpected bound variable #0

The full example is here:

import Lean
open Lean
partial def serialize_expression_ast (expr: Expr): MetaM String := do
  self expr
  where
  self (e: Expr): MetaM String :=
    match e with
    | .bvar deBruijnIndex =>
      pure s!"{deBruijnIndex}"
    | .fvar fvarId =>
      let name := fvarId.name.toString
      pure s!"(:fv {name})"
    | .mvar mvarId =>
      let name := mvarId.name.toString
      pure s!"(:mv {name})"
    | .sort _ =>
      pure s!"(:sort)"
    | .const declName _ =>
      -- The universe level of the const expression is elided since it should be
      -- inferrable from surrounding expression
      pure s!"(:c {declName})"
    | .app _ _ => do
      let fn'  self e.getAppFn
      let args := ( e.getAppArgs.mapM self) |>.toList
      let args := " ".intercalate args
      pure s!"({fn'} {args})"
    | .lam binderName binderType body binderInfo => do
      let binderName' := binderName.toString
      let binderType'  self binderType
      let body'  self body
      let binderInfo' := binder_info_to_ast binderInfo
      pure s!"(:lambda {binderName'} {binderType'} {body'}{binderInfo'})"
    | .forallE binderName binderType body binderInfo => do
      let binderName' := binderName.toString
      let binderType'  self binderType
      let body'  self body
      let binderInfo' := binder_info_to_ast binderInfo
      pure s!"(:forall {binderName'} {binderType'} {body'}{binderInfo'})"
    | .letE name type value body _ => do
      -- Dependent boolean flag diacarded
      let name' := name.toString
      let type'  self type
      let value'  self value
      let body'  self body
      pure s!"(:let {name'} {type'} {value'} {body'})"
    | .lit v =>
      -- To not burden the downstream parser who needs to handle this, the literal
      -- is wrapped in a :lit sexp.
      let v' := match v with
        | .natVal val => toString val
        | .strVal val => s!"\"{val}\""
      pure s!"(:lit {v'})"
    | .mdata _ inner =>
      -- NOTE: Equivalent to expr itself, but mdata influences the prettyprinter
      -- It may become necessary to incorporate the metadata.
      self inner
    | .proj typeName idx inner => do
      let env  getEnv
      let fieldName := getStructureFields env typeName |>.get! idx
      let inner  Meta.mkProjection inner fieldName
      assert! !inner.isProj
      self inner
  -- Elides all unhygenic names
  binder_info_to_ast : Lean.BinderInfo  String
    | .default => ""
    | .implicit => " :implicit"
    | .strictImplicit => " :strictImplicit"
    | .instImplicit => " :instImplicit"

def metaM: MetaM Unit := do
  let env  getEnv
  let symbol := "ULift.down".toName
  IO.println "Finding symbol"
  let info := env.find? symbol |>.get!
  IO.println "Finding value"
  let value := info.value? |>.get!
  IO.println "Printing"
  let expr := toString ( serialize_expression_ast value)
  IO.println s!"{expr}"

def main : IO Unit := do
  let env: Environment  importModules
    (imports := #["Init"].map (λ str => { module := str.toName, runtimeOnly := false }))
    (opts := {})
    (trustLevel := 1)
  let coreM := Meta.MetaM.run' metaM
  let coreContext: Lean.Core.Context := {
    currNamespace := "PrintExpr".toName,
    openDecls := [],     -- No 'open' directives needed
    fileName := "<stdin>",
    fileMap := { source := "", positions := #[0], lines := #[1] }
    options := Lean.Options.empty
  }
  match  (coreM.run' coreContext { env := env }).toBaseIO with
  | .error exception =>
    IO.println s!"{← exception.toMessageData.toString}"
  | .ok _            =>
    IO.println "Finished"

Notification Bot (Dec 06 2023 at 04:59):

Leni Aniva has marked this topic as unresolved.

Notification Bot (Dec 06 2023 at 05:03):

Leni Aniva has marked this topic as unresolved.

Notification Bot (Dec 06 2023 at 05:04):

Leni Aniva has marked this topic as resolved.

Notification Bot (Dec 06 2023 at 05:15):

Leni Aniva has marked this topic as unresolved.

Leni Aniva (Dec 06 2023 at 05:16):

Kyle Miller said:

I think you use docs#Lean.getStructureFields to get the field names, and then use docs#Lean.getFieldInfo? to get a structure that contains the projFn field.

It looks like there's docs#Lean.Meta.mkProjection, to create the Expr.app. It can also handle field names that are subfields (fields from a structure it extends)

Is there a function that doesn't require telescoping? Meta.mkProjection requires telescoping into the local context where the projection takes place. I feel like the projected type should be recoverable from the fields of Expr.proj

I'm currently using a structure like this:

| .proj typeName idx inner => do
      let env  getEnv
      let fieldName := getStructureFields env typeName |>.get! idx
      let projectorName := getProjFnForField? env typeName fieldName |>.get!
      let e := Expr.app (.const  projectorName []) inner
      -- e is now a projection in `.app` form

Last updated: Dec 20 2023 at 11:08 UTC