{"id":22933607,"url":"https://github.com/gustavodiasag/simpler","last_synced_at":"2025-10-10T14:34:35.374Z","repository":{"id":215025665,"uuid":"734508078","full_name":"gustavodiasag/SimPLer","owner":"gustavodiasag","description":"Interpreter for a functional, expression-based programming language","archived":false,"fork":false,"pushed_at":"2024-05-09T00:45:06.000Z","size":82,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-01T18:39:52.015Z","etag":null,"topics":["functional-programming","interpreter","lambda-calculus","ocaml","programming-language"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gustavodiasag.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-21T21:37:34.000Z","updated_at":"2024-05-09T00:45:09.000Z","dependencies_parsed_at":"2024-01-02T03:29:57.669Z","dependency_job_id":"a318b186-0721-443c-8d07-bf95e7edfcad","html_url":"https://github.com/gustavodiasag/SimPLer","commit_stats":{"total_commits":74,"total_committers":2,"mean_commits":37.0,"dds":0.04054054054054057,"last_synced_commit":"e0111154740a34e2e74f8ae64632a6945399bcac"},"previous_names":["gustavodiasag/simpler"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gustavodiasag/SimPLer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavodiasag%2FSimPLer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavodiasag%2FSimPLer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavodiasag%2FSimPLer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavodiasag%2FSimPLer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gustavodiasag","download_url":"https://codeload.github.com/gustavodiasag/SimPLer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavodiasag%2FSimPLer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279004172,"owners_count":26083688,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","interpreter","lambda-calculus","ocaml","programming-language"],"created_at":"2024-12-14T11:32:21.660Z","updated_at":"2025-10-10T14:34:35.345Z","avatar_url":"https://github.com/gustavodiasag.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SimPLer\n\n[![SimPLer](https://github.com/gustavodiasag/SimPLer/actions/workflows/test.yml/badge.svg)](https://github.com/gustavodiasag/SimPLer/actions/workflows/test.yml)\n\nImplementation of an interpreter for the SimPL and Core OCaml programming languages as the final exercise from the book [OCaml Programming: Correct + Efficient + Beautiful](https://cs3110.github.io/textbook/ocaml_programming.pdf). \n\nAlthough these toy languages are just basic calculators in some way (given that only expressions are supported), some ideas present in [lambda calculus theory](https://plato.stanford.edu/entries/lambda-calculus/) are provided by them, such as substitution and anonymous functions. Besides that, the languages are defined with syntactic and semantic rules very similar to those of OCaml.\n\nImportant excerpts from the book regarding the theoretical and mathematical aspects of the project are separately described in a [notes section](NOTES.md).\n\n# Specifications\n\n## Syntax\n\nThe syntax rules in the standard BNF notation for SimPL and Core Ocaml are presented below:\n\n### SimPL\n\n```\ne ::= x \n    | i \n    | b \n    | e binop e'\n    | if e then e' else e''\n    | let x = e in e'\n\nbinop ::= + | * | \u003c=\n\nx ::= \u003cidentifier\u003e\n\ni ::= \u003cinteger\u003e\n\nb ::= true | false\n```\n\n### Core OCaml\n\n```\ne ::= x \n    | e1 e2 \n    | fun x -\u003e e\n    | i \n    | b \n    | e1 bop e2\n    | (e1, e2)\n    | fst e \n    | snd e\n    | if e1 then e2 else e3\n    | let x = e1 in e2\n\nbop ::= + | * | \u003c | \u003e | = | \u003c= | \u003e= \n\nx ::= \u003cidentifier\u003e\n\ni ::= \u003cinteger\u003e\n\nb ::= true | false\n\nv ::= fun x -\u003e e | i | b | (v1, v2)\n```\n\n## Lexing and Parsing\n\nNeither the lexer nor the parser for the language are developed from scratch. Instead, the implementation relies on tools provided by the libraries [ocamllex](https://v2.ocaml.org/manual/lexyacc.html), responsible for the generation of lexical analyzers, and [Menhir](https://gallium.inria.fr/~fpottier/menhir/manual.pdf), responsible for the generation of parsers. \n\nThe details for the lexer definition (i.e., identifiers and rules) are found in [lexer.mll](lib/lexer.mll), and the details for the grammar definition (i.e., symbols and production rules) are found in [parser.mly](lib/parser.mly).\n\n## Evaluation\n\nThe process of simplifying the languages' [Abstract Syntax Tree](lib/ast.ml) down to a single value is defined through a mathematical relation whose style is known as **operational semantics**. More specifically, these semantics are divided in small step and big step semantics, where:\n\n- **Small step** semantics represent execution in terms of individual small steps, or how a program takes one single step of execution.\n\n- **Big step** semantics represent execution in terms of a big step from an expression directly to a value, abstracting away all the details of single steps.\n\nBoth styles are discussed by the book, but since big-step semantics are more similar to how an interpreter would actually be implemented, the languages' evaluation strategy is based only on this model.\n\n## Substitution\n\nThe implementation of variables use the **substitution model** of evaluation, where the value of a variable is substituted for its name throughout the scope of that name, as soon as a binding of the variable is found.\n\nFor SimPL (which is composed of expressions), the notation `e'{e/x}` is used to determine the expression `e'` with `e` substituted for `x`. So anywhere `x` appears in `e'`, it should be replaced with `e`. For Core OCaml, the same logic is applied, but since it supports a value abstraction, the notation changes slightly to `e{v/x}`. This model is defined for each of the languages' constructs, but given that Core OCaml is a superset of SimPL, only its rules are specified:\n\n### Constants\n\nVariables cannot appear in them (e.g., `x` cannot syntactically occur in `42`), so substitution leaves constants unchanged.\n\n```\ni{v/x} = i\n\nb{v/x} = b\n```\n\n### Operators and conditionals\n\nAll that substitution does is recurse inside the subexpressions.\n\n```\n(e1 + e2){v/x} = e1{v/x} + e2{v/x}\n\n(if e1 then e2 else e3){v/x} = if e1{v/x} then e2{v/x} else e3{v/x}\n```\n\n### Variables\n\nThere are two possibilities, either the variable to be substituted is found or not, in which case the substitution must not happen\n\n```\nx{v/x} = v\n\ny{v/x} = y\n```\n\n### Let expressions\n\nTwo cases are also possible, depending on the name of the bound variable. If a shadowed name has been reached, substitution must stop in order to prioritize the most recent binding, so it is only applied to the first expression. On the contrary, substitution carefully recurses inside both expressions, avoiding [capturing any variables](NOTES.md/#capture-avoiding-substitution-1139).\n\n```\n(let x = e1 in e2){v/x} = let x = e1{v/x} in e2\n\n(let y = e1 in e2){v/x} = let y = e1{v/x} in e2{v/x}\n    if y not in FV(v)\n```\n\n### Anonymous functions\n\nFundamentally the same as for \"let\" expressions.\n\n```\n(fun x -\u003e e'){v/x} = (fun x -\u003e e')\n\n(fun y -\u003e e'){v/x} = (fun y -\u003e e'{v/x})\n    if y not in FV(v)\n```\n\n### Tuples\n\n```\n(e1, e2){v/x} = (e1{v/x}, e2{v/x})\n\n(fst e){v/x} = fst (e{v/x})\n\n(snd e){v/x} = snd (e{v/x})\n```\n\n# License\n\nThe project is licensed under the [MIT License](LICENSE)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgustavodiasag%2Fsimpler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgustavodiasag%2Fsimpler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgustavodiasag%2Fsimpler/lists"}