{"id":26226848,"url":"https://github.com/hoetty/marble","last_synced_at":"2025-08-02T16:37:21.208Z","repository":{"id":279855899,"uuid":"940222510","full_name":"Hoetty/marble","owner":"Hoetty","description":"A simple and compact functional programming language","archived":false,"fork":false,"pushed_at":"2025-03-07T15:05:37.000Z","size":86,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-07T15:37:18.785Z","etag":null,"topics":["functional","functional-programming","programming-language"],"latest_commit_sha":null,"homepage":"https://hoetty.github.io/marble/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hoetty.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2025-02-27T20:11:55.000Z","updated_at":"2025-03-07T15:05:40.000Z","dependencies_parsed_at":"2025-02-28T05:02:31.420Z","dependency_job_id":"8007c8d3-62c3-4585-a90c-0c414921627a","html_url":"https://github.com/Hoetty/marble","commit_stats":null,"previous_names":["hoetty/marble"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hoetty%2Fmarble","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hoetty%2Fmarble/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hoetty%2Fmarble/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hoetty%2Fmarble/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hoetty","download_url":"https://codeload.github.com/Hoetty/marble/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243280856,"owners_count":20266092,"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","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","functional-programming","programming-language"],"created_at":"2025-03-12T19:31:15.617Z","updated_at":"2025-08-02T16:37:21.172Z","avatar_url":"https://github.com/Hoetty.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Marble\n\nMarble is a compact and simple functional programming language.\nIt is inspired by Lambda Calculus, Haskell and other functional programming languages and tries to do as much as possible with a minimal set of features.\n\nTry Marble at https://hoetty.github.io/marble/\n\n## Syntax \u0026 Using Marble\n\n### Literals\n\nAs in most programming languages, you can create number literals. However, unlike most programming languages, you cannot use digits for that.\n\nThese are some valid number literals:\n```\nFive\nFortyTwo\nTwoHundredTwentyOneMillionFiveHundredThirtyThousandEighteen\nThreePointOneFour\n```\n\n*You might argue, that this seems a little complex for the proclaimed minimal set of features, but it makes numbers follow the style of the rest of the language*\n\n### Strings\n\nString literals can be created by placing text between ```str``` and ```ing``` or using ```string``` to create an empty string.\n\n```\nstr Hello World ing\nstring\nstr 😀🤪 ing\n```\n\n### Comments\n\nComments follow a similar design as strings: A single line comment is started by ```comment``` and goes until the next newline; Everything inside the keywords ```com``` and ```ment``` is part of a multiline comment.\n\n```\ncomment This is a single line comment\n\ncom\nThis is a multiline comment\nHello!\nment\n```\n\n### Functions\n\nAs a functional language, marble also supports creating functions. Functions always accept one argument and must return exactly one value.\n\nHere is a function, that directly returns the given argument:\n```\nfn X do\n    X\nend\n```\n\nIdentifiers for function arguments may consist of any unicode character, except for space, tab, newline and the carriage return. This results from the fact, that the source code is parsed as words seperated by whitespace (with the expection of strings and comment). These identifiers are all valid:\n```\nX\nÖ\nß\n?\n😀\n-\n```\n*Note: Identifiers may shadow previous identifiers of the same name - you can declare the same variable name multiple times.*\n\nYou can call a function using the ```of``` operator:\n```\nPrintLn of str Hello World ing\n```\n\nAltough functions must accept exactly one argument, you can define functions that accept multiple values. This is possible through [```currying```](https://en.wikipedia.org/wiki/Currying) where a function returns another functions, which captures the argument of the first.\n\n```\nfn F X do\n    F of X\nend\n\nfn F do\n    fn X do\n        F of X\n    end\nend\n```\n*The second expression shows, how the first function is interpreted*\n\nThis implies, that you call a function that accepts multiple arguments using multiple ```of```s:\n```\nAdd of One of One\n```\n\nIf you want to pass the result of a function call to a function, you can group it using a ```do``` block.\n\n```\nAdd of Five of do Mul of Two of Two end\n```\n\n#### Builtin Functions\n\nMarble offers several builtin functions for common tasks and arithmetic:\n- Add/2: Adds its numerical arguments\n- Sub/2: Subtracts its numerical arguments\n- Mul/2: Multiplies its numerical arguments\n- Div/2: Divides its numerical arguments\n- Is/2: Tests if its arguments are equal\n- IsNot/2: Tests if its arguments are not equal\n- Print/1: Prints the argument\n- PrintLn/1: Prints the argument and a newline\n- And/2: Returns the second argument if the first argument is true, the first otherwise\n- Or/2: Returns the first argument if the first argument is true, the second otherwise\n\nAll builtin functions support partial application.\n\n### Let\n\nLike in other procedural programming languages, you can put values into variables. To do that, you can use ```let X be Y in```, which assigns Y to X for the following expression:\n\n```\nlet Greeting be str Hello World ing in\nPrintLn of Greeting\n```\n\nAltough ```let``` may look like ordinary variable assignment, it actually wraps the expression after ```in``` into a function, that accepts the variables name as argument and calls it using the given value. This is the let expression from above:\n\n```\nfn Greeting do\n    PrintLn of Greeting\nend of str Hello World ing\n```\n\nThis way variable assignment is actually an expression, that evaluates to the result of the following expression.\n\n### Then\n\nWhen programming, you often need to execute multiple statements after one another, for example printing multiple things. In Marble you can do this using ```then```:\n\n```\nPrint of str Hello  ing then\nPrint of str World ing\n```\n\nNote: The left side of a then expression must return a function, that accepts another function. The returned function will then receive the right side of the then expression, and is reponsible for executing it.\n\n### Control Flow\n\n#### Conditional\n\n```True``` and ```False``` are implemented as [Curch Booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans), meaning they are both functions that accept two arguments, where true returns the first, and false the second:\n\n```\ncomment True\nfn L R do\n    L\nend\n\ncomment False\nfn L R do\n    R\nend\n```\n\nYou can use the ```If``` function to conditionally return values:\n```\nIf of do Is of Ten of Ten end of One of Zero\ncomment One\n```\n\nAs ```True``` and ```False``` themselves return the first or second argument, they already work like if/the ternary operator, so you can just omit the call to the ```If``` function entirely:\n```\nIs of Ten of Ten of One of Zero\ncomment One\n```\n\n\u003e **Note**:\n\u003e\n\u003e In a normal programming language, all arguments to a function get evaluated before the function is called with the resulting values. This would make these control flow structures quite useless, as both arms would be executed, regardless of which one is chosen in the end. Therefore Marble employs [Lazy Evaluation](https://en.wikipedia.org/wiki/Lazy_evaluation), meaning values/expressions are only computed when their result is really needed, and values that are never used aren't executed either. Values are only ever forcefully evaluated when they are the return value of the program or the left hand side argument of a function call (when they are being called).\n\n#### Looping\n\nLooping (or repeated execution in general) is possible through the use of [combinators](https://en.wikipedia.org/wiki/Fixed-point_combinator), e. g. the Y-Combinator. The Y Combinator provides a function with a reference to itself, so that it can call itself recursively. Here is an example implementation of the recursive factorial function using the Y-Combinator:\n```\nlet Y be fn F do\n    let G be fn X do \n        F of do X of X end \n    end in\n    G of G\nend in\n\nlet Fact be fn Fact N do\n    Is of N of Zero of do\n        One\n    end of do\n        Mul of N of do Fact of do Sub of N of One end end\n    end\nend in\n\nlet Fact be Y of Fact in\n\nFact of Five\ncomment 120\n```\n\nYou dont need to reimplement the combinators every time you use them though, you can import the Y and the Z combinator from ```lang/y``` and ```lang/z``` respectively.\n\n### Imports\n\nYou can use the builtin ```Import``` function, to import another script. The Import function will resolve to the value provided by the script. You should call the ```Import``` function using a string that is either ```lang/\u003c..\u003e``` to retrieve a language defined value or provide a path to another .mrbl script relative to the currents scripts location. When specifying the path, omit the ```.mrbl``` file extension.\n\nConsider the following directory structure:\n```\n- src\n  - file1.mrbl\n  - file2.mrbl\n  - folder1\n    - file3.mrbl\n```\n\nTo import file2 from file1 you would specify ```file2```, to import file3 you would specify ```folder1/file3```.\nTo import file2 from file3 you would specify ```../file2```.\n\n\u003e **Note**\n\u003e\n\u003e Importing a file will fully evaluate it each time. This means two files, that both import each other directly will cause a recursion error.\n\n### Data Structures\n\n#### Tuples\nYou can construct a tuple to hold exactly 2 items using the ```Tuple``` function from ```lang/tuple```:\n```\nTuple of One of Two\n```\n\nThe first value can be extracted from the tuple using the ```TFirst``` function from ```lang/tfirst```, the second one using ```TSecond``` from ```lang/tsecond```:\n```\nlet OneTwo be Tuple of One of Two in\nPrintLn of do TFirst of OneTwo end then\nPrintLn of do TSecond of OneTwo end then\nUnit\n```\n\n*Implementation Details:*\nThe ```Tuple``` function constructs a function that accepts another function and calls that with the contained values:\n```\nfn L R Get do\n    Get of L of R\nend\n```\n\nTo get the first element of the tuple, ```True``` is passed to it, as it returns the first of its two arguments; so ```TFirst``` is defined as:\n```\nfn T do\n    T of True\nend\n```\nSimilarly, ```TSecond``` is defined using ```False```:\n```\nfn T do\n    T of False\nend\n```\n\n### Pro Tips\n- You can also use let and curried functions, to create functions, where one argument is already defined: \n    ```\n    let AddThree be Add of Three in\n    AddThree of Three\n    ```\n\n- If you don't like the number literals, you can just assign the ones you would like to use:\n    ```\n    let 3 be Three in\n    Add of 3 of 3\n    ```\n- If you don't like the operator functions, you can just assign the ones you would like to use:\n    ```\n    let + be Add in\n    + of Three of Three\n    ```\n\n### Design Notes\n\nThrough the implemention of ```let``` and ```then``` through function calls, every Marble program is only a single expression, comprised of only literals, functions and calls.\n\n## Editor Support\n\nA VS Code Extension for syntax hightlighting is available under ```/marble-language-support```\n\n## Running Marble Programs\n\nThe marble executable lives under ```imarble```. Nacvigate there first:\n```sh\ncd imarble\n```\n\nYou can then build the project using cargo and enter an interactive REPL using:\n```sh\ncargo run -r\n```\n\nIf you want to execute a file, you should pass the path to the file as an argument:\n```sh\ncargo run -r -- path/to/my/file.mrbl\n```\n\n## Planned Improvements\n- Performance: The current implementation is pretty slow.\n- Maybe maybe a language server","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoetty%2Fmarble","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhoetty%2Fmarble","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoetty%2Fmarble/lists"}