lean4-htt/library/init/lean/parser/rec.lean
Leonardo de Moura 42fbe3c18c chore(library/init,runtime,library/compiler): add fix primitive back
The new `partial def`s allow us to define `fix` in Lean, but the Lean
implementation is not as efficient as the native one. The native one
in C++ use weak pointers to prevent a closure allocation at every
recursive invocation.

This commit also fixes the `fixCore` helper functions that were broken
after we switched to camelCase.

We have updated the test `fix1.lean` to demonstrate the native
implementation is faster. Here are the numbers on my desktop.

```
./run.sh fix1.lean 24
721420279
Time for 'native fix': 816ms
721420279
Time for 'fix in lean': 1.34s
```
2019-03-27 17:13:53 -07:00

56 lines
2.1 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.
Author: Sebastian Ullrich
Recursion monad transformer
-/
prelude
import init.control.reader init.lean.parser.parsec init.fix
namespace Lean.Parser
/-- A small wrapper of `ReaderT` that simplifies introducing and invoking
recursion points in a computation. -/
def RecT (α δ : Type) (m : Type → Type) (β : Type) :=
ReaderT (α → m δ) m β
namespace RecT
variables {m : Type → Type} {α δ β : Type} [Monad m]
local attribute [reducible] RecT
/-- Continue at the recursion point stored at `run`. -/
@[inline] def recurse (a : α) : RecT α δ m δ :=
λ f, f a
/-- Execute `x`, executing `rec a` whenever `recurse a` is called.
After `maxRec` recursion steps, `base` is executed instead. -/
@[inline] protected def run (x : RecT α δ m β) (base : α → m δ) (rec : α → RecT α δ m δ) : m β :=
x (fixCore base (λ a f, rec f a))
@[inline] protected def runParsec {γ : Type} [MonadParsec γ m] (x : RecT α δ m β) (rec : α → RecT α δ m δ) : m β :=
RecT.run x (λ _, MonadParsec.error "RecT.runParsec: no progress") rec
-- not clear how to auto-derive these given the additional constraints
instance : Monad (RecT α δ m) := inferInstance
instance [Alternative m] : Alternative (RecT α δ m) := inferInstance
instance : HasMonadLift m (RecT α δ m) := inferInstance
instance (ε) [MonadExcept ε m] : MonadExcept ε (RecT α δ m) := inferInstance
instance (μ) [MonadParsec μ m] : MonadParsec μ (RecT α δ m) :=
inferInstance
-- NOTE: does not allow to vary `m` because of its occurrence in the Reader State
instance [Monad m] : MonadFunctor m m (RecT α δ m) (RecT α δ m) :=
inferInstance
end RecT
class MonadRec (α δ : outParam Type) (m : Type → Type) :=
(recurse {} : α → m δ)
export MonadRec (recurse)
instance MonadRec.trans (α δ m m') [HasMonadLift m m'] [MonadRec α δ m] [Monad m] : MonadRec α δ m' :=
{ recurse := λ a, monadLift (recurse a : m δ) }
instance MonadRec.base (α δ m) [Monad m] : MonadRec α δ (RecT α δ m) :=
{ recurse := RecT.recurse }
end Lean.Parser