Giter VIP home page Giter VIP logo

elsa's Introduction

ELSA

elsa is a tiny language designed to build intuition about how the Lambda Calculus, or more generally, computation-by-substitution works. Rather than the usual interpreter that grinds lambda terms down to values, elsa aims to be a light-weight proof checker that determines whether, under a given sequence of definitions, a particular term reduces to to another.

Online Demo

You can try elsa online at this link

Install

You can locally build and run elsa by

  1. Installing stack
  2. Cloning this repo
  3. Building elsa with stack.

That is, to say

$ curl -sSL https://get.haskellstack.org/ | sh
$ git clone https://github.com/ucsd-progsys/elsa.git
$ cd elsa
$ stack install

Editor Plugins

Overview

elsa programs look like:

-- id_0.lc
let id   = \x -> x
let zero = \f x -> x

eval id_zero :
  id zero
  =d> (\x -> x) (\f x -> x)   -- expand definitions
  =a> (\z -> z) (\f x -> x)   -- alpha rename
  =b> (\f x -> x)             -- beta reduce
  =d> zero                    -- expand definitions

eval id_zero_tr :
  id zero  
  =*> zero                    -- transitive reductions

When you run elsa on the above, you should get the following output:

$ elsa ex1.lc

OK id_zero, id_zero_tr.

Partial Evaluation

If instead you write a partial sequence of reductions, i.e. where the last term can still be further reduced:

-- succ_1_bad.lc
let one  = \f x -> f x
let two  = \f x -> f (f x)
let incr = \n f x -> f (n f x)

eval succ_one :
  incr one
  =d> (\n f x -> f (n f x)) (\f x -> f x)
  =b> \f x -> f ((\f x -> f x) f x)
  =b> \f x -> f ((\x -> f x) x)

Then elsa will complain that

$ elsa ex2.lc

ex2.lc:11:7-30: succ_one can be further reduced

  11  |   =b> \f x -> f ((\x -> f x) x)
              ^^^^^^^^^^^^^^^^^^^^^^^^^

You can fix the error by completing the reduction

-- succ_1.lc
let one  = \f x -> f x
let two  = \f x -> f (f x)
let incr = \n f x -> f (n f x)

eval succ_one :
  incr one
  =d> (\n f x -> f (n f x)) (\f x -> f x)
  =b> \f x -> f ((\f x -> f x) f x)
  =b> \f x -> f ((\x -> f x) x)
  =b> \f x -> f (f x)                 -- beta-reduce the above
  =d> two                             -- optional

Similarly, elsa rejects the following program,

-- id_0_bad.lc
let id   = \x -> x
let zero = \f x -> x

eval id_zero :
  id zero
  =b> (\f x -> x)
  =d> zero

with the error

$ elsa ex4.lc

ex4.lc:7:5-20: id_zero has an invalid beta-reduction

   7  |   =b> (\f x -> x)
          ^^^^^^^^^^^^^^^

You can fix the error by inserting the appropriate intermediate term as shown in id_0.lc above.

Syntax of elsa Programs

An elsa program has the form

-- definitions
[let <id> = <term>]+

-- reductions
[<reduction>]*

where the basic elements are lambda-calulus terms

<term> ::=  <id>
          \ <id>+ -> <term>
            (<term> <term>)

and id are lower-case identifiers

<id>   ::= x, y, z, ...

A <reduction> is a sequence of terms chained together with a <step>

<reduction> ::= eval <id> : <term> (<step> <term>)*

<step>      ::= =a>   -- alpha equivalence
                =b>   -- beta  equivalence
                =d>   -- def   equivalence
                =*>   -- trans equivalence
                =~>   -- normalizes to

Semantics of elsa programs

A reduction of the form t_1 s_1 t_2 s_2 ... t_n is valid if

  • Each t_i s_i t_i+1 is valid, and
  • t_n is in normal form (i.e. cannot be further beta-reduced.)

Furthermore, a step of the form

  • t =a> t' is valid if t and t' are equivalent up to alpha-renaming,
  • t =b> t' is valid if t beta-reduces to t' in a single step,
  • t =d> t' is valid if t and t' are identical after let-expansion.
  • t =*> t' is valid if t and t' are in the reflexive, transitive closure of the union of the above three relations.
  • t =~> t' is valid if t normalizes to t'.

(Due to Michael Borkowski)

The difference between =*> and =~> is as follows.

  • t =*> t' is any sequence of zero or more steps from t to t'. So if you are working forwards from the start, backwards from the end, or a combination of both, you could use =*> as a quick check to see if you're on the right track.

  • t =~> t' says that t reduces to t' in zero or more steps and that t' is in normal form (i.e. t' cannot be reduced further). This means you can only place it as the final step.

So elsa would accept these three

eval ex1:
  (\x y -> x y) (\x -> x) b 
  =*> b

eval ex2:
  (\x y -> x y) (\x -> x) b 
  =~> b

eval ex3:
  (\x y -> x y) (\x -> x) (\z -> z) 
  =*> (\x -> x) (\z -> z) 
  =b> (\z -> z)

but elsa would not accept

eval ex3:
  (\x y -> x y) (\x -> x) (\z -> z) 
  =~> (\x -> x) (\z -> z) 
  =b> (\z -> z)

because the right hand side of =~> can still be reduced further.

elsa's People

Contributors

cole-k avatar glapa-grossklag avatar jevancc avatar justinyaodu avatar lkuper avatar mb64 avatar ranjitjhala avatar rejectedcode avatar rosekunkel avatar themattchan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

elsa's Issues

Recursive definitions?

This fails, where (4) is derived from the fact that (3) contains (2)


let Y = \f -> (\x -> f (x x)) (\x -> f (x x))

eval Yg_gYg :
  Y g
  =d> (\f -> (\x -> f (x x)) (\x -> f (x x))) g    -- 1
  =b> (\x -> g (x x)) (\x -> g (x x))              -- 2
  =b> g ((\x -> g (x x)) (\x -> g (x x)))          -- 3
  =d> g (Y g)                                      -- 4

Check duplicate definition and evaluation identifiers

Currently, elsa does not check duplicate definition and evaluation identifiers. For example:

let TRUE = \x y -> x
{- some definitions here -}
let TRUE = \x y -> y  -- should be named FALSE

eval true_x_y :
  TRUE x y
  =~> x

else will raise an invalid reduction error since the second definition overwrites the first one, which is hard for developers to debug.

Similarily, elsa allows multiple evaluations to have the same identifiers:

let id   = \x -> x

eval id_x :
  id x
  =d> (\x -> x) x
  =b> x

eval id_x :      -- duplicate identifier
  id x
  =~> x

Even though it does not harm the correctness, it may confuse developers since the cli displays the evaluation name and occurrence when there is an error.

Beta reduction scoping/alphatizing error

The following valid reduction fails:

eval and_true_false :
  AND TRUE FALSE
...
  =b> (\x y -> (\x y -> x) x y)  (\x y -> y) FALSE
  =b> (\y -> (\x y -> x) (\x y -> y) y) FALSE
  ...
  =d> FALSE

with error

01_bool.lc:35:3-7: and_true_false has an invalid reduction!

        35|    =b> (\y -> (\x y -> x) (\x y -> y) y) FALSE
               ^^^^

I think using a de Bruijn-based representation internally will fix this? (Not sure if that's already the case)

Parse error locations

let THD3   = \t -> t \x y z -> z

gives a gross error -- point out line, column to be useful!

Oddness with normalization?

Via @nadiapolikarpova

Here's a permalink just in case:

http://goto.ucsd.edu:8095/index.html#?demo=permalink%2F1554145341_1040.lc

In the below, even_four checks okay as is, but even_three fails.

However, if you uncomment the intermediate steps, then it succeeds.

Maybe has to do with the semantics of =*> and =~> ?

let TRUE  = \x y -> x
let FALSE = \x y -> y
let ITE   = \b x y -> b x y
let NOT = \b x y -> b y x
let ZERO  = \f x -> x
let ONE   = \f x -> f x
let TWO   = \f x -> f (f x)
let THREE = \f x -> f (f (f x))
let FOUR  = \f x -> f (f (f (f x)))
let EVEN = \n -> n NOT TRUE
  
eval even_four:
  EVEN FOUR
  =~> TRUE  
  
eval even_three:
  EVEN THREE
  -- =d> (\n -> n NOT TRUE) THREE
  -- =b> THREE NOT TRUE
  -- =d> (\f x -> f (f (f x))) NOT TRUE
  -- =b> (\x -> NOT (NOT (NOT x))) TRUE
  -- =b> NOT (NOT (NOT TRUE))
  -- =*> NOT (NOT FALSE)
  -- =*> NOT TRUE
  =~> FALSE

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.