Zulip Chat Archive

Stream: general

Topic: Lea(r)n you a scheme


Chris B (Mar 11 2020 at 18:59):

I was flipping through this thing where you implement a version of scheme in Haskell. I'm curious whether there are any clever ways of implementing the given definition of the LispVal type in Lean. Trying to power through it as a mutual inductive (with a ListLispVal type to avoid nesting and making IFunc, and Eval part of the mutual) is no good since you end up with a negative occurrence in the Fun constructor.

In Haskell the whole thing is :

data LispVal =
    Atom T.Text
  | List [LispVal]
  | Number Integer
  | String T.Text
  | Fun IFunc
  | Lambda IFunc EnvCtx
  | Nil
  | Bool Bool

data IFunc = IFunc { fn :: [LispVal] -> Eval LispVal }
type EnvCtx = Map.Map T.Text LispVal
newtype Eval a = Eval { unEval :: ReaderT EnvCtx IO a }

In sort of pseudo-lean :

inductive LispVal
| Atom : string -> LispVal
| List : list LispVal -> LispVal
| Number : ℤ → LispVal
| String : string → LispVal
| Fun : IFunc → LispVal
| Lambda : IFunc → EnvCtx → LispVal
| Nil : LispVal
| Bool : bool → LispVal

structure IFunc :=
(fn : list LispVal → Eval LispVal)

def EnvCtx := KVMap string LispVal

structure Eval (A : Type) :=
(un_eval : reader_t EnvCtx io A)

Mario Carneiro (Mar 11 2020 at 19:18):

You can't represent these functions as functions in lean, because of nontermination

Mario Carneiro (Mar 11 2020 at 19:19):

If you are okay with meta you can do it, and if you are okay with adding termination conditions then I think you can do it as well

Chris B (Mar 11 2020 at 19:36):

You would still have to make some significant change to the type definition or break it up though right, since meta doesn't lift the ban on negative occurrences?
For termination condition do you just mean like gas?

Mario Carneiro (Mar 11 2020 at 20:18):

meta does lift the ban on negative occurrences

meta inductive term
| app : term  term  term
| lam : (term  term)  term

Mario Carneiro (Mar 11 2020 at 20:25):

import system.io

meta def EnvCtx := native.rb_map string
meta structure IFunc (A : Type) :=
(fn : list A  reader_t (EnvCtx A) io A)

meta inductive LispVal : Type
| Atom : string  LispVal
| List : list LispVal  LispVal
| Number :   LispVal
| String : string  LispVal
| Fun : IFunc LispVal  LispVal
| Lambda : IFunc LispVal  EnvCtx LispVal  LispVal
| Nil : LispVal
| Bool : bool  LispVal

Mario Carneiro (Mar 11 2020 at 20:31):

@Sebastian Ullrich Can you still do things like this in lean 4?

Mario Carneiro (Mar 11 2020 at 20:32):

neither partial nor unsafe seems to cover this use case for meta

Chris B (Mar 11 2020 at 20:59):

I guess you have to say the m word to get it to break.

** invalid mutually inductive type, non-positive occurrence in introduction rule: term -> term

meta mutual inductive term, val
with term : Type
| app : term  term  term
| lam : (term  term)  term
with val : Type
| mk : val

Chris B (Mar 11 2020 at 21:04):

That's a better definition than what I was trying to do anyway. Is the accepted way to newtype something to make it a def and mark it as irreducible, or is there another convention?

Mario Carneiro (Mar 11 2020 at 21:13):

structure gives you the most "newtype"-like semantics

Mario Carneiro (Mar 11 2020 at 21:13):

def is more like a typedef

Sebastian Ullrich (Mar 11 2020 at 21:40):

@Mario Carneiro sure https://github.com/leanprover/lean4/blob/5b296cbb33ac156ab262f231acb4f6cccc432056/tests/lean/run/inliner_loop.lean#L1


Last updated: Dec 20 2023 at 11:08 UTC