lean4-htt/src/Lean/Data/Options.lean
Leonardo de Moura 5ffbada3df feat: add Lean.MonadEnv, Lean.MonadError, and Lean.MonadOptions
This is the first set of polymorphic methods. I will add more later,
and keep reducing code duplication.

cc @Kha
2020-08-22 16:00:43 -07:00

118 lines
4.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich and Leonardo de Moura
-/
import Lean.Data.KVMap
namespace Lean
def Options := KVMap
namespace Options
def empty : Options := { : KVMap }
instance : HasEmptyc Options := ⟨empty⟩
instance : Inhabited Options := ⟨empty⟩
instance : HasToString Options := inferInstanceAs (HasToString KVMap)
end Options
structure OptionDecl :=
(defValue : DataValue)
(group : String := "")
(descr : String := "")
def OptionDecls := NameMap OptionDecl
instance OptionDecls.inhabited : Inhabited OptionDecls :=
⟨({} : NameMap OptionDecl)⟩
private def initOptionDeclsRef : IO (IO.Ref OptionDecls) :=
IO.mkRef (mkNameMap OptionDecl)
@[init initOptionDeclsRef]
private constant optionDeclsRef : IO.Ref OptionDecls := arbitrary _
@[export lean_register_option]
def registerOption (name : Name) (decl : OptionDecl) : IO Unit := do
decls ← optionDeclsRef.get;
when (decls.contains name) $
throw $ IO.userError ("invalid option declaration '" ++ toString name ++ "', option already exists");
optionDeclsRef.set $ decls.insert name decl
def getOptionDecls : IO OptionDecls := optionDeclsRef.get
@[export lean_get_option_decls_array]
def getOptionDeclsArray : IO (Array (Name × OptionDecl)) := do
decls ← getOptionDecls;
pure $ decls.fold
(fun (r : Array (Name × OptionDecl)) k v => r.push (k, v))
#[]
def getOptionDecl (name : Name) : IO OptionDecl := do
decls ← getOptionDecls;
(some decl) ← pure (decls.find? name) | throw $ IO.userError ("unknown option '" ++ toString name ++ "'");
pure decl
def getOptionDefaulValue (name : Name) : IO DataValue := do
decl ← getOptionDecl name;
pure decl.defValue
def getOptionDescr (name : Name) : IO String := do
decl ← getOptionDecl name;
pure decl.descr
def setOptionFromString (opts : Options) (entry : String) : IO Options := do
let ps := (entry.splitOn "=").map String.trim;
[key, val] ← pure ps | throw $ IO.userError "invalid configuration option entry, it must be of the form '<key> = <value>'";
defValue ← getOptionDefaulValue key.toName;
match defValue with
| DataValue.ofString v => pure $ opts.setString key val
| DataValue.ofBool v =>
if key == "true" then pure $ opts.setBool key true
else if key == "false" then pure $ opts.setBool key false
else throw $ IO.userError ("invalid Bool option value '" ++ val ++ "'")
| DataValue.ofName v => pure $ opts.setName key val.toName
| DataValue.ofNat v =>
match val.toNat? with
| none => throw (IO.userError ("invalid Nat option value '" ++ val ++ "'"))
| some v => pure $ opts.setNat key v
| DataValue.ofInt v =>
match val.toInt? with
| none => throw (IO.userError ("invalid Int option value '" ++ val ++ "'"))
| some v => pure $ opts.setInt key v
@[init] def verboseOption : IO Unit :=
registerOption `verbose { defValue := true, group := "", descr := "disable/enable verbose messages" }
@[init] def timeoutOption : IO Unit :=
registerOption `timeout { defValue := DataValue.ofNat 0, group := "", descr := "the (deterministic) timeout is measured as the maximum of memory allocations (in thousands) per task, the default is unbounded" }
@[init] def maxMemoryOption : IO Unit :=
registerOption `maxMemory { defValue := DataValue.ofNat 2048, group := "", descr := "maximum amount of memory available for Lean in megabytes" }
class MonadOptions (m : Type → Type) :=
(getOptions : m Options)
export MonadOptions (getOptions)
/- We currently cannot mark the following definition as an instance since it increases the search space too much -/
def monadOptsFromLift (m) {n} [MonadOptions m] [HasMonadLiftT m n] : MonadOptions n :=
{ getOptions := liftM (getOptions : m _) }
instance ReaderT.monadOpts {ρ m} [MonadOptions m] : MonadOptions (ReaderT ρ m) := monadOptsFromLift m
instance StateRefT.monadOpts {σ m} [MonadOptions m] : MonadOptions (StateRefT σ m) := monadOptsFromLift m
section Methods
variables {m : Type → Type} [Monad m] [MonadOptions m]
def getBoolOption (k : Name) (defValue := false) : m Bool := do
opts ← getOptions;
pure $ opts.getBool k defValue
def getNatOption (k : Name) (defValue := 0) : m Nat := do
opts ← getOptions;
pure $ opts.getNat k defValue
end Methods
end Lean