Zulip Chat Archive
Stream: lean4
Topic: MergeMap env extension
Tomas Skrivan (Apr 13 2023 at 23:53):
Lean has a builtin env extension that can map declarations to arbitrary data. The problem is that you can add data only in the same file as the declaration. This is a limitation that is not working for me. So I wrote a MergeMapDeclarationExtension
which is exactly like MapDeclarationExtension
but it merges the data from different files.
The MergeMapDeclarationExtension
seems to work nicely but I'm a bit concerned with performance. I'm really unsure how to utilize the ImportM
monad. I would appreciate any comments on how to improve this. Or better, doesn't matlib or std have this already?
Tomas Skrivan (Apr 13 2023 at 23:54):
the code
import Std.Data.RBMap.Alter
open Lean
def Array.joinlM [Monad m] [Inhabited β] (xs : Array α) (map : α → m β) (op : β → β → m β) : m β := do
if h : 0 < xs.size then
xs[1:].foldlM (init:=(← map xs[0])) λ acc x => do op acc (← map x)
else
pure default
def Array.joinl [Inhabited β] (xs : Array α) (map : α → β) (op : β → β → β) : β := Id.run do
xs.joinlM map op
namespace Lean
structure MergeMapDeclarationExtension.Merge (α) where
merge : Name → α → α → α
is_valid : ∀ n a b c, merge n (merge n a b) c = merge n a (merge n b c)
∧
∀ n a b, merge n a b = merge n b a
open MergeMapDeclarationExtension in
/--
Similar to `MapDeclarationExtension` but it allows you to insert declarations that were not declared in the same file.
However, you have to provide how to merge the values and to guarantee consistency i.e. merging should be associative and commutative.
-/
def MergeMapDeclarationExtension (α)
:= PersistentEnvExtension (Name × α) (Name × α) (Std.RBMap Name α Name.quickCmp)
open MergeMapDeclarationExtension in
def mkMergeMapDeclarationExtension [Inhabited α] (merge : Merge α) (name : Name := by exact decl_name%)
: IO (MergeMapDeclarationExtension α) :=
registerPersistentEnvExtension {
name := name
mkInitial := pure default
addImportedFn := fun s =>
let m := (s.map λ s' => .ofArray s' _) |>.joinl id λ a b => .mergeWith merge.1 a b
pure m
addEntryFn := fun s (n,val') => (s.alter n (λ val? => match val? with | .some val => merge.1 n val val' | none => val'))
exportEntriesFn := fun s => s.toList.toArray
}
namespace MergeMapDeclarationExtension
instance : Inhabited (MergeMapDeclarationExtension α) :=
inferInstanceAs (Inhabited (PersistentEnvExtension ..))
variable {m} [Monad m] [MonadEnv m]
def insert (ext : MergeMapDeclarationExtension α) (declName : Name) (val : α) : m Unit :=
modifyEnv (λ env => ext.addEntry env (declName, val))
def find? [Inhabited α] (ext : MergeMapDeclarationExtension α) (declName : Name) : m (Option α) := do
return (ext.getState (← getEnv)).find? declName
def contains [Inhabited α] (ext : MergeMapDeclarationExtension α) (declName : Name) : m Bool := do
return (ext.getState (← getEnv)).contains declName
end MergeMapDeclarationExtension
Last updated: Dec 20 2023 at 11:08 UTC