{"id":18017886,"url":"https://github.com/zac-garby/pluto-lang","last_synced_at":"2026-03-08T18:37:48.778Z","repository":{"id":116696104,"uuid":"96619079","full_name":"zac-garby/pluto-lang","owner":"zac-garby","description":"A language with a strange function syntax.","archived":false,"fork":false,"pushed_at":"2017-08-29T16:30:57.000Z","size":962,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-22T08:01:44.334Z","etag":null,"topics":["concept","language","pluto","programming-language","python","python3"],"latest_commit_sha":null,"homepage":"http://pluto.zacgarby.co.uk","language":"Python","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/zac-garby.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":"2017-07-08T12:56:37.000Z","updated_at":"2023-09-04T12:28:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"c6b7078f-4bfa-4b62-9347-423765b46a04","html_url":"https://github.com/zac-garby/pluto-lang","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zac-garby%2Fpluto-lang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zac-garby%2Fpluto-lang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zac-garby%2Fpluto-lang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zac-garby%2Fpluto-lang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zac-garby","download_url":"https://codeload.github.com/zac-garby/pluto-lang/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245722813,"owners_count":20661830,"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":["concept","language","pluto","programming-language","python","python3"],"created_at":"2024-10-30T04:26:03.784Z","updated_at":"2026-03-08T18:37:48.729Z","avatar_url":"https://github.com/zac-garby.png","language":"Python","readme":"# This is the **old, Python version** of Pluto.\n## Find the new version [here!](https://github.com/Zac-Garby/pluto)\n\n---\n\n## What?\n\nPluto is a language with a cool function definition/call syntax. Basically, instead of functions\nbeing called with their arguments in parentheses after the name, they are represented by their patterns:\n\n```r\n# defines a pattern: 'this is a pattern'\ndef this is a pattern {\n  ...\n}\n\nthis is a pattern\n```\n\nThis snippet defines a function with a pattern of \"this is a pattern\". Then, whenever a function call is\nfound, it searches through all the patterns which have been defined and calls the matching one. Coincidentally\nthis happens on the next line. It matches the pattern and calls whatever's inside the body.\n\nFunctions can, of course, also take parameters:\n\n```r\ndef evaluate $number times $multiplier {\n  number * multiplier\n}\n\nevaluate 5 times 10\n```\n\nThis program results in  the value `50`. Hopefully, you can see why. In  a pattern in a function  definition,\nwhen you have a dollar sign before an identifier it means that  it's a parameter. Then, when you call it, you\nplace an expression inside brackets at that position. Note that, inside the  function body, you don't use the\ndollar signs before the variable names. The brackets are required  to resolve any ambiguity.\n\nAnother thing -  the pattern in the above examples are  really very  verbose, so it's  probably a bad idea to\nmake a pattern that long, as it would take longer to type out. For vague guidelines, you might want to have a\nlook at the **very** tiny standard library. A couple of them are\nquite long, but they're probably less used than the others so  the longer length doesn't matter, and improves\nreadability significantly.\n\n![Screenshot](screenshot.png)\n\n_(note: This language is **incredibly** slow, since it's written in Python. It doesn't matter, as it's just a prototype. However, I'm planning on rewriting in a faster language in the future)_\n\n### Other expressions as arguments\n\nImagine this:\n\n```r\ndef double $n {\n  n * 2\n}\n\ndouble 5 + 3\n```\n\nWhat would you expect to happen? My guess would be for it to return `16`. But it doesnt - it actually returns\n`13`. This is because it actually parses  the function call as `double`, then  the literal `5`, which is then\nadded to the other literal `3`. Essentially, it's equivalent to this:\n\n```r\n(double 5) + 3\n```\n\nSo how do you avoid this? Well, since the reason it didn't work last time is because  the invisibile brackets\nare in the wrong place, so you just need to tell them where to go:\n\n```r\ndouble (5 + 3)\n```\n\nThis will now give you the result you wanted.\n\nAnother problem you might come across is this:\n\n```r\ndef $a plus $b {\n  a + b\n}\n```\n\nHow would you call this? If you did the following:\n\n```r\n5 plus 10\n```\n\nYou'd get an error. This is because the current grammar only allows for _implicit function calls_ if the first\nitem in the pattern is an identifier, and not an argument. In this case, you need to use an _explicit function call_:\n\n```r\n\\5 plus 10\n```\n\nThis would work exactly as you'd expect, returning the value `15`.\n\n## Defining your own if expression\n\nBecause of the function calling  syntax, you can actually define your  own pseudo-syntactical constructs. For\nexample, you could create a function which does the exact same thing as an if expression:\n\n```r\ndef if $condition then $a else $b {\n  if (condition) {\n    a\n  } else {\n    b\n  }\n}\n```\n\nFirst things first: this is the first time you've seen an if expression in this language. They're fairly\nstandard. One main difference is that they're expressions, not statements, like in some other languages.\n\nYou can then call it like this:\n\n```r\n\\if (true) then 5 else 10\n```\n\nWhich, as you can probably guess, will return 5. A few things to mention: you need to use a\nbackslash before the custom-defined if function, because otherwise it will parse it as a\nnormal if expression. Also, `true` has to be in a set of parentheses because otherwise it will be\nparsed as a normal identifier in the pattern.\n\nThis is really cool because, in theory, you could even define the English language as a series of functions!\n\n## Match expressions\n\nInstead of switch-case statements, Pluto has match expressions, similar to Rust:\n\n```r\na = 7\n\nstring = match (a) {\n  1 =\u003e \"one\"\n  2 =\u003e \"two\"\n  3 =\u003e \"three\"\n  4 =\u003e \"four\"\n  5, 6, 7, 8, 9, 10 =\u003e {\n    print \"A large number has been found\"\n    \"quite big\"\n  }\n  * =\u003e \"something else\"\n}\n```\n\nThey're similar to switch-cases, but with a nicer syntax, and also they're expressions instead of statements. When\nevaluating a match expression, it goes through each \"arm\", and if the value in brackets at the top is equal to any\nexpression in the list before the arrow, it returns the _statement_ on the right, without checking any other arms.\n\nAlso, a wildcard will match anything, so make sure it always comes last.\n\n## Blocks\n\nThere exists a type known as a block. Here's one:\n\n```r\nmy_block = {\n  print \"Hello, world\"\n}\n```\n\nA block basically stores a block of code inside it, which can then be executed on cue, using the `do $block` builtin:\n\n```r\ndo $my_block\n```\n\nThis piece of code prints \"Hello, world\" to the console. Like functions, blocks can recieve arguments:\n\n```r\nadd = { |a, b| -\u003e a + b }\n\ndo $add with [3, 10]\n```\n\nThis block, called `add`, takes two arguments: `a`, and `b`. It then returns the sum of them. As you can see, to run a\nblock with arguments, you use the `do $block with $args` builtin, providing the arguments as an array.\n\nAn interesting note is that both `do $block` and `do $block with $args` are both defined as normal functions.\n\nBlocks are also used in some functions in the standard library:\n\n```r\nmap { |n| -\u003e n * n } over [1, 2, 3, 4, 5]  #-\u003e [1, 4, 9, 16, 25]\nfold [1, 2, 3, 4, 5] with { |counter, n| -\u003e counter + n }  #-\u003e 15\n```\n\n## Collections\n\nA lot of functions in the standard library operate on what's called a _collection_. A collection is a type which can be\nrepresented as a list of elements. There are three collection types currently defined:\n\n - Array (you've already seen this one)\n - Strings are also collections!\n - A new type: Tuples\n \nBefore getting into tuples, here's an example using different types of collections:\n\n```r\n\u003e\u003e\u003e map { |x| -\u003e x * 2; } over [1, 2, 3, 4, 5]\n[2, 4, 6, 8, 10]\n\n\u003e\u003e\u003e map { |x| -\u003e x + \"!\"; } over \"foo\"\nf!o!o!\n```\n\nJust like you've seen before. Now, onto tuples:\n\n```r\na_tuple = (1, 2, 3)\njust_one = (1,)\nempty = ()\n```\n\nHere are three examples of tuples. As you can see, they're defined exactly like lists, except from using normal brackets\ninstead of square ones.\n\nYou can loop over tuples, just like arrays:\n\n```r\nfor (i : a_tuple) {\n  print $i\n}\n```\n\n### Operators on collections\n\nA few operators are defined on collections:\n\n - `+` - adds the two collections together\n - `-` - returns the first list with all shared elements removed\n - `\u0026` or `\u0026\u0026` - returns the intersection of the two collections\n - `|` or `||` - returns the union of the two collections\n \n## Maps\n\nMaps are similar to dictionaries in Python, or objects in JavaScript:\n\n```r\na_map = [\n  \"x\": 3,\n  \"y\": -7,\n  true: \"A boolean can also be a key ...\",\n  3: \"... as can a number!\",\n]\n```\n\n**Something quite important in this example is that there is a trailing comma in the map literal. This is because the**\n**literal spans multiple lines, so automatic semicolon insertion would insert a semicolon in place of the last comma, had**\n**it not been put there explicitly. For this reason, commas are always allowed in map and array literals.**\n\nThe syntax is similar to that of an array literal, however between each comma is a `key: value` mapping. You can access\na value at a certain key with the `key $key of $obj` builtin:\n\n```r\nkey \"y\" of $a_map\n```\n\nWhich, of course, returns `-7`.\n\n### Maps as collections\n\nMaps are not collections. This is because there's no good option for what the elements should be. The keys? The\nvalues? Or even, an array containing tuples in the format `(key, value)`. All of these are equally useful, so instead\nof making maps collections directly, three builtins are defined:\n\n```r\nkeys of $obj\nvalues of $obj\npairs of $obj\n```\n\nThese return the keys, values, and tuple-pairs, respectively, of $obj. These allow for the use of anything collections do:\n\n```r\nme = [\"name\": \"Zac\", \"age\": 15]\n\nfor (key : keys of $me) {\n  printf \"%s: %s\" with (key, key $key of $me)\n}\n```\n\n## Classes\n\nPluto supports some object oriented features, namely classes and inheritance. The class syntax is fairly straightforward:\n\n```r\nclass Point {\n  init at $x $y {\n    self.x = x\n    self.y = y\n  }\n  \n  def move by $x $y {\n    self.x = self.x + x\n    self.y = self.y + y\n  }\n}\n```\n\nAn `init` method is a constructor, meaning you can instantiate a `Point` with the following syntax:\n\n```r\nmy_point = Point at 10 3\n```\n\nInternally what happens is, when an `init` method is defined, a normal function is defined in the same scope as the\nclass declaration which creates a new instance of the class, then evaluates the body of the class with that instance.\n\nTherefore, you can override `init` methods, as well as normal functions, which can be useful sometimes.\n\nTo call a method on a class instance, you use the `\u003cinstance\u003e: \u003cpattern\u003e` syntax, like so:\n  \n```r\nmy_point: move by (-10) (-3)\n\nprint (my_point.x)\n```\n\nWhich will print `0.0`. Something interesting to point out is that the values `-10` and `-3` are surrounded in brackets.\nThis is because, at the moment, the syntax doesn't allow for unary operators in patterns without brackets round them,\nalthough I'd like to change this at some point.\n\n### Inheritance\n\nYou can also use inheritance in your classes. I'll probably add an example here at some point, but for now, have a look\nat `examples/classes.pluto` to see how.\n\n## Error handling\n\nA lot of the time when programming, you'll get errors, such as `This argument is of an unexpected type`:\n\n```r\ndo \"This is not a block\"\n```\n\nSince the string `\"This is not a block\"` isn't a block (remember: the `do $` function executes a block), an error\nis thrown:\n\n```r\nTypeError: the $block parameter must be of type \u003cblock\u003e, not \u003cstring\u003e\n```\n\nWhich is expected. But what if you don't care about this problem? Maybe you want to do something when you encounter an\nerror; or, just skip past it. To do that, you'd use a _try-catch_ block:\n\n```r\ntry {\n  do \"This is not a block\"\n} catch (err) {\n  Type =\u003e {\n    print \"An error occurred!\"\n  }\n}\n```\n\nThis piece of code, instead of giving you an error message, will just print `\"An error occurred!\"`. This has the same\npowerful syntax as _match_ expressions, so you can write code like this:\n\n```r\ntry { ... } catch (err) {\n  Type, IO =\u003e {\n    print \"A type or IO error occurred!\"\n  }\n  \n  * =\u003e {\n    print \"Some other error occurred\"\n  }\n}\n```\n\n### Throwing errors\n\nAs well as catching already-thrown errors, Pluto also allows you to throw your own. This would be useful if you write a\nfunction in which something can go wrong, and you want to let other people know. You throw an error using the error\nconstructor, a tag, and a message:\n\n```r\nError $General \"This is an error!\"\n```\n\nA `General` error signifies a generic, possibly unknown, error, but there are more types available to you. These are\ntheir names:\n\n```r\nGeneral\nType\nIO\nOutOfBounds\nNotFound\nSyntax\nNotImplemented\nAssertion\n```\n\nWhich can then be caught in exactly the same way. Since they are literally just strings defined in the Prelude, you are\nfree to make your own error tags. They don't even have to be strings - but it's usually better for them to be.\n\n### Assertions\n\nAnother (very useful) way of throwing errors is through the assertion builtins:\n\n```r\nassert $predicate\nassert $predicate else $msg\n\n# (where $predicate is a block)\n```\n\nThe first one, `assert $predicate`, will throw an error if `$predicate` returns a falsey value. The error will have the\ntag `Assertion`, and the message will be `\"An assertion failed!\"`.\n\nThe second one is very similar. It has the exact same semantics, except instead of the default message `\"An assertion failed!\"`,\n`$msg` is used.\n\n## How??\n\nTo use it, clone the repository and run `__main__.py`. Giving it no arguments will run the REPL, in which you can enter\nstatements line by line.\n\nThere are also a number of arguments you can use:\n\nArgument            | Description\n--------------------|-----------------------------------------------------\n`-f, --file`        | Runs the given file\n`-p, --parse`       | Parses the file, but doesn't execute it\n`-t, --tree`        | Parses the file and prints the parse tree\n`-i, --interactive` | Runs the file and enters interactive mode afterwards\n`-h, --help`        | Shows a useful help menu\n`-n, --no-prelude`  | Doesn't load the prelude\n`-v, --version`     | Shows the current version\n\n## Contributions\n\nAny contributions are welcome. Just send a pull request. I'll probably accept it if it adds anything useful.\n\n### What can I do?\n\nThere are loads of things to do. Heres a list for you:\n\n - Extend the standard library. Literally, put any function in and I'll probably accept it.\n - Write up some better documentation.\n - Add testing.\n - Change syntax so explicit function calls are only necessary with a pattern of length 1.\n - Only throw a syntax error if one hasn't already been thrown in the same statement, to avoid repetition.\n - Rewrite in a faster language - possibly Rust or Go.\n - Add type conversions (maybe `\"val -\u003e type\"` or `\"val as type\"`)\n - Add sorting builtins\n - Add importing files\n - Add a module system\n - Make unary operators allowed in patterns\n - Maybe add a regex literal\n - Add a better way of doing string interpolation, maybe `\"hello {{x}} {{y + x}}\"?`\n - (very tricky,) compile Pluto code to bytecode, to speed up execution\n - Add more examples\n - Convert some language constructs to builtin functions\n - Add more functional/higher order functions\n - Improve error messages\n - Add list (and map?) comprehensions\n - Change syntax to reduce use of braces (maybe terminating with 'end'?)\n - Add some kind of meta-programming support\n - Add a literate Pluto file type\n - Allow blocks to be curried, and hence partially applied\n - Add stacktraces in errors\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzac-garby%2Fpluto-lang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzac-garby%2Fpluto-lang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzac-garby%2Fpluto-lang/lists"}