Lamb Da Calculus Calculator Term Project

Transcription

Lambda Calculus CalculatorTerm ProjectDepartment of Computer ScienceUniversity of Applied Science RapperswilFall Term 2018Author(s):Advisor:Cyrill Hänni, Dominik KesslerProf. Dr. Farhad D. Mehta

Contents1 Management Summary1.1 Introduction . . . . . .1.2 Approach . . . . . . .1.3 Result . . . . . . . . .1.4 Outlook . . . . . . . .2 Abstract3 Framework Evaluation3.1 PureScript . . . . . . . .3.2 Haskell to JS Transpilers3.3 ReasonML . . . . . . . .3.4 Elm . . . . . . . . . . .3.5 ReasonML vs Elm . . .3.6 Decision . . . . . . . . .444456.77788994 ELM Quality Measures104.1 IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104.2 Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104.3 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Introduction to Lambda Calculus5.1 Introduction . . . . . . . . . . . .5.2 Syntax . . . . . . . . . . . . . . .5.3 Alpha Conversion . . . . . . . . .5.4 Beta Reduction . . . . . . . . . .5.5 Delta Reduction . . . . . . . . .5.6 Normal Form . . . . . . . . . . .5.7 Evaluation Strategies . . . . . . .5.7.1 Innermost Leftmost First5.7.2 Outermost Leftmost First6 De6.16.26.3.12121213131313141414Bruijn Index15The Problem with α-conversions . . . . . . . . . . . . . . . . . . 15Encoding Variables with De Bruijn Index . . . . . . . . . . . . . 15Shift Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Architectural Overview172

8 Parser8.1 Syntax . . . . . . . . . . . . . . . .8.1.1 Letter Lambda λ . . . . . .8.1.2 Variable Names . . . . . . .8.1.3 White Spaces . . . . . . . .8.1.4 Predicates . . . . . . . . . .8.2 Resulting Data Structure . . . . .8.2.1 Function Headers . . . . . .8.2.2 Predicate and LambdaTerm8.3 Parser Implementation . . . . . . .8.3.1 elm/parser Library . . . . .8.3.2 Parsing Steps . . . . . . . .8.3.3 Parsing . . . . . . . . . . .8.3.4 Left Association . . . . . .8.3.5 De Bruijn Index . . . . . . . . . . . . . . . . . . . . . . . . . . .Types. . . . . . . . . . . . . . . . . . .1818181818191919202020212122239 Reducer9.1 Strategies . . . . . . . . . . . . . . . . . .9.1.1 Example Outermost First Strategy9.2 Flow - reduceWithStrategy . . . . . . . .9.3 Reduction Modules . . . . . . . . . . . . .9.3.1 Example Beta-Reduction . . . . .25252627282910 Frontend10.1 Introduction . . . . .10.2 Architecture . . . . .10.2.1 Action . . . .10.2.2 Model (State)10.2.3 Updater . . .10.2.4 View . . . . .10.3 Styling . . . . . . . .10.3.1 Bootstrap . .10.3.2 Fontawesome10.3.3 SASS . . . .303031313232323434343411 Build Process11.1 Local build and deployment . . . . . . . . . . . .11.1.1 How start the project for development? .11.1.2 How to build the project for deployment?11.1.3 How to run unit tests? . . . . . . . . . . .11.1.4 How to setup elm-format? . . . . . . . . .11.2 CI / CD . . . . . . . . . . . . . . . . . . . . . . .11.2.1 Continuous Integration (CI) . . . . . . . .11.2.2 Continuous Deployment (CD) . . . . . . .353535363636363636.A Bibliography.373

Chapter 1Management Summary1.1IntroductionLambda calculus is the mathematical basis of functional programming and oftenused to teach it. There are currently a few lambda calculus interpreters available, but all of them suffer from a complicated user experience, an unappealinguser interface and require too much effort to understand.The purpose of the term project ”Lambda Calculus Calculator” is to write auser friendly lambda calculus interpreter, which can be used to teach lambdacalculus right from the beginning.1.2ApproachAfter a short evaluation phase at the beginning, we switched to an agile approachfor the rest of the project. The first, very limited MVP1 was ready after the thirdweek. Since then we always had a functioning application that we improvedcontinuously.1.3ResultThe outcome of the study project is a single page web application written inthe functional programming language elm. The focus of the application lies onthe derivation of lambda terms, which can either be reduced manually or byselecting a strategy.Lambda Calculus Calculator supports three different reduction methods: βreductions, δ-reductions and number resolution, as well as two different resolution strategies: outermost first and innermost first.1 MinimalViable Product4

1.4OutlookThere are still features that could be added, which would be helpful for moreadvanced users. Because of this, the project will be released to the open sourcecommunity, so that anyone can contribute to it.We hope that other universities will start adopting Lambda Calculus Calculatorto teach lambda calculus.There are also plans to create a similar application, which can benefit from thefoundation we built, for sequent calculus.5

Chapter 2AbstractProf. Dr. Farhad Mehta realised that there are no user friendly lambda calculusinterpreters available to teach lambda calculus. Therefore, he decided to proposethe term project ”Lambda Calculus Calculator”.In contrast to the existing solutions, Lambda Calculus Calculator should be userfriendly and targeted at beginners. Not only should it be able to reduce a lambdaterm to its normal form, but also visualise all the intermediate steps.To make the product as approachable as possible, it was implemented as a singlepage web application. The interpreter provides the functionality to reduce termsby using either predefined strategies and rewrite rules, or to let the users definetheir rules and strategies themselves.Moreover, the application also allows users to try different derivation paths forthe same term. The user can switch between these paths at any time to comparedifferent strategies.The lambda term reducer is easily extensible with new reduction strategies andrewrite rules. This was purposely done as the plan is to release the project tothe open source community, so everybody can contribute to the project.6

Chapter 3Framework EvaluationWe want to use a statically typed, functional programming language, which canbe compiled to JavaScript, so it can run completely in the users browser.Currently there are a few options available but there is no a clear industryfavourite. In the following paragraphs, we will compare the available options.An important point for us is that the language should not be to experimentalor short lived, so the project can be maintained for a long time.3.1PureScriptWe looked into PureScript1 and although we liked the language features, theUI frameworks (Pux2 and Halogen3 ) do not seem to be ready for productiveuse. They are slow, development seems to be stagnant and there are almost noquestions about them on stackoverflow45 .3.2Haskell to JS TranspilersHaskell to JS compilers also do not seem to be used in production. There aretwo competing compilers (GHCJS6 and Haste7 ) and none of them seem to beactively developed on GitHub. There is a frontend library called miso8 but itdoesn’t seem to be used in production either. Just like with Pux and Halogne,there are almost no questions regarding it on Stackoverflow9 .Personally, we think that the future of Haskell in the browser will be a WebAssembly compiler such as asterius10 , and not a JavaScript transpiler. How1 [27]PureScriptPux3 [28] halogen4 [34] Stackoverflow search results: purescript halogen5 [36] Stackoverflow search results: purescript pux6 [20] GHCJS7 [23] Haste8 [25] miso9 [35] Stackoverflow search results: Haskell miso10 [1] Asterius: a Haskell to WebAssembly compiler2 [29]7

ever, we do not want to rely on WebAssembly at this point as, according tocaniuse.com11 , it is only available for about 80% of all web users.However, we still started to work on a sample application with GCHJS andMiso. First, we faced some issues with installing the correct Haskell toolchain.Once we managed that, we started a build which took 4 hours on the UbuntuBash on Windows. Even if we could somehow speed it up by a factor of ten, itstill would not be acceptable.3.3ReasonMLReason12 is a new syntax for the OCaml language. It was developed by Facebookto make OCaml more approachable for JavaScript Developers by providing asimilar syntax.To transpile Reason or OCaml code into JavaScript, the bucklescript13 transpileris used.ReasonReact14 is a library, that allows the popular React library to be usedwith a statically typed, functional programming language. Just like React,ReasonML supports writing HTML in JSX. This means it is possible to writeHTML tags directly in the source files.The big drawback of ReasonML is that it is still a very young language. Its initialrelease was only in April of 201615 and that version was still far away from beingproduction ready. Since then it developed a lot, but still stackoverflow activityfor ReasonML is about 7 times lower than that of Elm16 .3.4ElmElm17 is a programming language, which at first glance, looks very similar toHaskell but it intentionally lacks some of the more complex Haskell features,such as type classes. This makes it easier to learn at the expense of expressibility, which can be frustrating for experienced Haskell developers. The languagealready includes a UI framework.Elm was first released in April of 201218 and is therefore one of the older availableoptions. This means that the language had more time to develop and for thecommunity to grow, indicated by the relatively high activity on stackoverflow19 .In addition to that, there are a lot of open source 3rd party libraries availablefor the elm package manager20 .11 [4]Can I use WebAssembly?ReasonML13 [3] BuckleScript14 [32] ReasonReact15 [10] ReasonML initial release16 [30] Questions tagged with ”reason” on stackoverflow (1413)17 [5] Elm-lang18 [9] Elm - Release Notes19 [11] Questions tagged with ”elm” on stackoverflow (1413)20 [8] Elm Packages12 [31]8

3.5ReasonML vs ElmPurescript (especially the frontend libraries) and Haskell to JavaScript transpilers just feel too experimental to be used for a project of this scale. Due tothis reasons we focus on ReasonML and Elm in the following section. We implemented a simple todo app in both languages and compiled the comparisiontable below.CriteriaReasonMLElmProject setupSimpleSimpleCompiler ErrorsVery cryptic, hard to figureout where exactly the problem isBest we have seenin any languageSyntaxJavascript likeHaskell likeState ManagementState per componentOne global state(can be split, like inredux)Type ClassesNot Supported, but supportsOCaml modulesNot SupportedTest Libraryjest (bs-jest)elm-testStack overflow activity193 tagged questions1413 tagged questions3.6DecisionConsidering all the above, we came to the conclusion that elm is the most suitable framework for the term project. The main reasons are the bigger community, more available open source packages and the closer syntax to Haskell.9

Chapter 4ELM Quality MeasuresElm has recently been updated to version 0.191 and introduced breaking changes,which means some of the plugins and tools are not compatible anymore. However, since the project should last for a while we decided to still go with the latestversion. We will regularly check for updated versions for the broken plugins andif it makes sense we will include them in our development process.4.1IDEAs an IDE we decided to use Visual Studio Code2 with the elm-lang extension3 . This combination provides everything we expect from a code editor likesyntax highlighting, compiler warnings and much more. Additionally, it easilyintegrates with the other tools we decided to use. Unfortunately, there are norefactoring tools included in the extension.4.2FormattingWe decided to follow the style guide of elm-lang4 . There is a npm package5which formats the elm-files according to the standard guide and integrates wellwith the elm-lang extension for Visual Studio Code.4.3TestingFor everything except the UI, we will write unit tests with elm-test6 . If we finda bug at a later stage we first will write a test before we fix the code.Since the user interface changes a lot during the development process, we willnot write unit tests for the UI. Doing otherwise would cause too much overhead1 [9]Elm release notesVisual Studio Code3 [14] ELM Extension for Visual Studio Code4 [17] ELM Style Guide5 [15] ELM-Format tool6 [18] ELM Testing Library2 [38]10

in our opinion. We will however, test the UI by hand after every feature we implement. Testing the UI is also part of the merge-request review process.Code Coverage With the change to elm 0.19 a new of the testing libraryhas been introduced and therefore the code coverage plugin7 is not compatibleanymore. However, as previously mentioned, we will regularly check for anupdate.7 [13]Elm Test Coverage Library11

Chapter 5Introduction to LambdaCalculusIn this section we will explore Lambda Calculus in order to define the functional requirements for this application. The topics are based on the booklet”Introduction to Formal Proof and the Lambda Calculus” by Prof. Dr. FarhadMehta1 .5.1IntroductionLambda calculus was invented by Alonso Church in the 1930s. It is formalmathematical system and was proven to be Turing complete by Alan Turing in1937.2With a syntax that can be described with only two definitions, it is a veryminimal and elegant programming language.Lambda calculus is the basis of functional programming and often used as away to teach this programming paradigm.5.2SyntaxLambda Calculus divides its syntax in the two components: Predicates (P) andλ-Terms (M).P :: M MM :: x λx.M M MThe Term ”x” represents a variable, the term ”λx.M ” is an abstraction withthe parameter x and the body M. An abstraction is usually called a functionin programming languages. ”M M” stands for the application of one term to1 [24]2 [37]Lecture NotesAlan M. Turing: Computability and λ-Definability12

the other. Application is left associative which means M1 M2 M3 is equivalentto((M1 M2 )M3 ). Furthermore, application binds stronger than function, e.gλx.M1 M2 is interpreted as (λx.(M1 M2 ))5.3Alpha ConversionAn alpha conversion or α-conversion, is the action of renaming a bound variable in an abstraction. It only changes the textual representation of a term,functionally the term will still be equivalent.λx.x x λy.y y5.4Beta ReductionBeta reduction or β-reduction is the application of a term to an abstraction. Theequivalent in programming is usually called ”calling a function”. For M1 M2 ,this means to use the λ-term M2 as the argument of the λ-term M1 where M1is an abstraction.(λx.negate 5.5x)10 0.βnegate 1Delta ReductionLambda Calculus provides the option of naming λ-terms using predicates, e.g.x M . A δ-reduction is the action of replacing a (free) variable with itsdefinition.negate λx.(( 0)x) 5.6negate 10 0(λx.( 0) x) 10 0( 0) 10 0.δ.β.βNormal FormA λ-term is in its normal form, if there are no further reductions possible. Theexample in the section Beta Reduction is in its normal form. A property ofLambda Calculus is, that there is at most one normal form. This means thatit is also possible that a term has no normal form, as shown in the followingexample3 :3 Underlinemarks redex, selected for reduction.13

5.7(λx.xx)(λx.xx)0 0 (λx.xx)(λx.xx)0 0 .β.βEvaluation StrategiesA term that can be reduced by either β or δ reduction is also called a redex(short for reducible expression).A λ-term can have several redexes and there are several evaluation strategies todecide which redex to reduce next.This is important because not all strategies will always find a normal form. Inthis chapter we will only look at the two strategies which were part of the lectureat HSR.5.7.1Innermost Leftmost FirstAn innermost redex is a term that does not contain any more redexes. Therecan be multiple innermost redexes in a λ-term.1. Choose the innermost redex2. If there are more than one innermost redexes, choose the leftmost innermost redexThis means that an argument gets reduced before it gets applied. The innermostfirst strategy does not find a normal form for every case as shown in the followingexample:(λy.a)((λx.xx)(λx.xx))0 0(λy.a)((λx.xx)(λx.xx))0 0 5.7.2.β.β.Outermost Leftmost FirstAn outermost redex is not contained in any redexes. There can be multipleoutermost redexes in a λ-term.1. Choose the outermost redex2. If there are more than one outermost redexes, choose the leftmost outermost redexThis means that an argument gets reduced only after it has been applied. Theoutermost strategy will always find the normal form if the term has one. Letslook at how the outermost first strategy would solve the term that the innermoststrategy was unable to reduce to its normal form:(λy.a)((λx.xx)(λx.xx))0 0a0 0 14.β.β

Chapter 6De Bruijn Index6.1The Problem with α-conversionsDe Bruijn Indexing1 is a way to remove the need for α-conversions on nameclashes.Let us look at an example where alpha conversion is required:((λy.λx.y) x) a α((λy.λz.y) x) a β(λz.x) a βxIf we had omitted the alpha conversion, this would have been the result:((λy.λx.y) x) a β(λx.x) a βaAs seen, it would not have produced the correct result x but a. The problemhere is (λx.x) on the second line. The second x is not actually the boundvariable x but a free variable x that just happens to have the same name as thefirst x but we have no way of differentiating the two.There are many rules that say when an α-conversion is needed and when it isnot, but fortunately we do not have to take any of them into consideration whenusing De Bruijn Indices.6.2Encoding Variables with De Bruijn IndexDe Bruijn Indices only affect how abstractions and variables are written.1 [26]De Bruijn indexing in the untyped Lambda-Calculus15

Instead of writing the name of a bound variable, we only write a pointer toits binder. The binder is the abstraction to which the variable is bound. Forexample, in λx.x, λx. is the binder for x.The pointer is a number which indicates in how many abstraction the variableis enclosed in, starting at 0. E.g. λx.x becomes λ.0 and λx.λy.x y becomesλ.λ.1 0.Free variables do not belong to a binder. The number of abstractions the freevariable is enclosed in, is smaller than the index of the variable. The indexvalue is calculated by adding a number found in a lookup table and the numberof abstractions the free variable is surrounded by. For example a becomes 1and λx.a becomes λ.2. However, this encoding has no benefit and therefore, wedecided to not use it in the project.A lambda term encoded using De Bruijn Indices is definitely less human readablethan named bound variables, but that is not relevant. The goal is to make αreductions redundant and therefore simplify β- and δ-reductions.While displaying the term to the user it will be converted into a readable, namedparameter representation.6.3Shift OperationsDuring β-reductions it often happens that the number of abstractions in whicha bound variable is enclosed varies. Lets look at the following example, first inthe named parameter form to make it easier to read:λx.((λy.x) a) βλx.xThe same thing using De Bruijn Indices looks like this:λ.((λ.1) a) βλ.0Note that the shift operation was already applied in the example above, if wewould not have done so, the result would have been λ.1, which is not equivalentto the desired result of λx.x.The shift operation corrects the index, when the number of enclosing abstractions changes.16

Chapter 7Architectural OverviewThe architecture consists of the three main components the parser, the reducerand the frontend. These three components interact with each other to form theapplication.Frontend As the name suggests, the frontend is responsible to render the userinterface and handling user inputs. Based on the term entered by the user. Thefrontend first calls the parser to convert the input text into a data structurebefore calling the reducer with that data structure for the reduction operations.See chapter 10 ”Frontend” on page 30.Parser The parser receives a String from the frontend and tries to parse itto a LambdaTerm which will be returned back to the frontend. If the parserfails, an error will be returned. See chapter 8 ”Parser” on page 18.Reducer As the name implied the reducer is responsible to apply reductionsto lambda terms. It receives a LambdaTerm and some additional inputs andreturns the reduced LambdaTerm . See chapter 9 ”Reducer” on page 25.17

Chapter 8ParserThe job of a parser is to convert a string to a data structure, that can be usedfor further processing.In our case, it should convert a lambda calculus term, entered by the user, intoa data structure, which will be used as the input for the reducer described inthe next chapter.8.1SyntaxBefore discussing the parser, we need to define the syntax we will be using. Wewant it to be as close to the syntax described in chapter 5 as possible. As areminder, this is what that syntax looks like:P :: M MM :: x λx.M M M8.1.1Letter Lambda λInstead of encoding the lambda symbol with another symbol, we decided to usethe UTF-8 symbol λ directlyFor usability reasons, we will allow the user to use backslashes instead of the λsymbol. The conversion will be done in the UI and the parser does not need toknow about that.8.1.2Variable NamesVariable names (x) can consist of one or more UTF-8 characters, except forsome reserved characters like ”(”, ”)”, ”.” and ”λ”.8.1.3White SpacesWhite spaces are used to separate variable names, all other occurrences will beignored.18

8.1.4PredicatesThe definition of P :: M M quite straight forward to implement whenwe already have an implementation of M . The problem with that simple definition is that we do not have a way to differentiate between free variables andconstants.The following two examples demonstrate why that is important:Example 1 Assume we have a predicate (y y a) and a lambda term (b y).If we interpret y as a free variable, then the whole term (b y) can be unifiedwith y and the resulting term will be (b y a).If, on the other hand, we interpret y as a constant, then only y in (b y) unifieswith y and the reduced term will be (b y).Example 2 Maybe a more relatable example is the predicate (plusOne x x 1). Here we want plusOne to be a constant, but x to be a free variable sothat (plusOne 10) results in ( 10 1) when the delta reduction is appliedNow we know why we need to differentiate between constants and free variables,we need to decide on how to do so. It could either be done by having a listof constants or by having a list of free variables. We decided on the list offree variables, on the basis, that usually in programming languages we definevariables and not the things that are not variables.Syntax This is how the before mentioned plusOne predicate would looks likein our syntax: x.plusOne x x 1All free variables need to be defined between the universal quantifier symbol ( )and the the dot (.). Multiple free variables can be separated by whitespaces. Ifa symbol is not defined as a free variable, it will be interpreted as a constant,e.g. plusOne. The free variable definition block is optional. If it is omitted, allvariables will be interpreted as constants.8.28.2.1Resulting Data StructureFunction HeadersThe LambdaParser elm module exposes two functions: parseLambdaTerm andparsePredicate. This is how their type definitions look like:parseLambdaTerm : String - Result ParserError LambdaTermparsePredicate : String - Result ParserError PredicateBoth functions take a String and produce a Result of the respective type( LambdaTerm or Predicate ).19

The result type is part of the elm/core library (standard library) and can eitherbe an error or a result. In contrast to the Maybe type it cannot only represent whether there is a result or not, but also what went wrong in case of anerror.8.2.2Predicate and LambdaTerm TypesP :: M MM :: x λx.M M MThis is the syntax that we want to represent with the following types:type alias Predicate { freeVariables : Set String, left : LambdaTerm, right : LambdaTerm}type LambdaTerm Abstraction UniqueVariableName LambdaTerm BoundVariable BoundIndex FreeVariable VariableName Application LambdaTerm LambdaTermM is equivalent to LambdaTerm , Abstraction is λx.M and Application isM M.Instead of having one constructor for variables, we have two: BoundVariableand FreeVariable . The reason why we decided to do that is, that the differentiation of the two gives us some advantages in the reducer. Only variables oftype BoundVariable are encoded using de Bruijn index, see chapter 6. For thefree variables it does not make much sense to do so, because in the reducer wefrequently compare the value of multiple free variables which would generatetoo much overhead due to all the lookups.In addition to a LambdaTerm left and a LambdaTerm right the Predicate typealso includes the set of free variables inside this predicate, described in thesection before this.8.38.3.1Parser Implementationelm/parser LibraryThanks to the elm/parser 1 library, the implementation turned out to be simplerthan we anticipated. It took us a while to find out the best way to use it butafter that it was quite straight forward.The way a parser is written using elm/parser is very declarative:type alias LambdaTermList 1 [16]elm/parser library20

List LambdaTermParsedtype LambdaTermParsed Abstraction VariableName LambdaTermParsed Variable VariableName TermList LambdaTermList -- type definitiontermInParenthesis inContext ParsingTermInParenthesis -- only for error messagessucceed LambdaTermParsed.TermList . symbol "(" . spaces lazy (\ - inContext ParsingTermInParenthesis lambdaTermList) . spaces . symbol ")"This is an example of how a term in parenthesis, like (a b), is parsed. Theoptional inCotext . is there to generate more precise error messages. Theimportant bit starts with the succeed function. Its first argument is a function,in our case a type constructor function. This is the type that the parser shouldproduce if it is successful.After the required return type comes the actual parsing code. There are twodifferent functions we need to differentiate here: . means expect somethingbut ignore it and means expect something and memorise it. If you arefamiliar with regular expressions, is comparable to a capturing group.If we look at the termInParenthesis we see that it starts with an open parenthesis "(" , followed by an arbitrary amount of whitespaces. This is followedby the important part, a lambdaTermList, which will be handled in its ownfunction. The lazy part is there for back propagation. In this case, the lambdaTermList is the only part that we keep.When we look at the definition of LambdaTermBeforeLeftAssociation.TermList ,we see that it takes a single argument of type LambdaTermList , so the parsingdefinition has to return exactly one element of that type. If LambdaTermBeforeLeftAssociation.TermListhad more than one parameter, we would have to have more than one element.8.3.2Parsing StepsDue to some limitation in the parsing library and requirements of the reducer,we split the parsing into the three steps: Parsing, resolving left associativelyand finally conversion to De Bruijn encoded terms.8.3.3ParsingThe first step is to convert a String , entered by a user, to a LambdaTermParseddata structure using the elm/parser library described above.21

Data Structure This step results in the data structure we have seen in theelm/parser example above:type alias VariableName Stringtype alias LambdaTermList List LambdaTermParsedtype LambdaTermParsed Abstraction VariableName LambdaTermParsed Variable VariableName TermList LambdaTermListExample"λx.a b"-- will be converted to:Abstraction "x" (TermList [Variable "a", Variable "b"])8.3.4Left AssociationLambdaTermParsed does not yet include a representation for applications. Instead it contains a list of lambda terms. The goal of this step is to convert thisLambdaTermList to nested Application s.Data Structure Abstraction and Variable are basically the same as in theprevious data structure. The difference lies in the Application , which replacesTermList :type LambdaTermLeftAssociated Abstraction VariableName LambdaTermLeftAssociated Variable VariableName Application LambdaTermLeftAssociated LambdaTermLeftAssociatedExampleTermList [Variable "a", Variable "b", Variable "c"]-- will be converted to:Application (Application (Variable "a") (Variable "b")) (Variable "c")22

8.3.5De Bruijn IndexThe final step of the parser is to split the variables into bound- and free variables, while encoding the bound variables using De Bruijn Indices in the sameprocess.In the end, the resulting data structure will be traversed one final time to makeevery variable name unique by incrementing a counter every time the samevariable name occurs. This counter can then be used in the UI to help usersdifferentiate between multiple variables with the same name.Data Structure The Variable constructor from the previous step has beensplit into separate constructors for BoundVariable and FreeVariable . Toincorporate the requiremen

There are currently a few lambda calculus interpreters avail-able, but all of them su er from a complicated user experience, an unappealing user interface and require too much e ort to understand. The purpose of the term project "Lambda Calculus Calculator" is to write a user friendly lambda calculus interpreter, which can be used to teach lambda