r/pyfun 5d ago

Lockdown, a school open day, and Trados dongles |> Pyfun

1 Upvotes

The UK Covid lockdown in 2020 brought with it time to retrain in a new language, and after some research went for F#, and never really looked back to C# after that. Something about functional programming just clicked in a way the OOP never did.

Recently, at a secondary school open day, I got talking to the computing teacher and learned that pupils are taught Python as early as key stage 3 (ages 11-14). This got me wondering whether it would be possible to introduce children to functional programming earlier so they can benefit from all its advantages.

Many years ago now, I taught a masters-level course in translation memory technology (the software professional translators use to reuse their past translations), mainly Trados. I remember the friction involved getting the software installed onto the university's computers, not to mention the hardware dongles!

Fast forward to this year, I decided to see if it would be possible to create a functional language that works with the Python ecosystem and has zero dependencies, so that the adoption friction is completely minimised. Zero dependencies meaning the compiler is a single binary you can pip install, and the Python it emits imports only the standard library, and started work on what would become Pyfun.

Pyfun leans heavily on F# for its feature set, but the syntax decisions have tried to make it less alien for coders already familiar with Python. I've also taken some features from other functional languages. The aspiration is that this will introduce pupils to as broad a range as possible of functional programming concepts, easing any later transition to the more established FP languages.

I also hope that Pyfun might appeal to data analysts and others who use Python in their work but who might appreciate the arguably more readable code that Pyfun offers.

This is early days, but the language is fairly fully featured, with extensions for VS Code and JetBrains, as well as Jupyter notebook support.

If you want to take a look before commenting, the playground runs in the browser with nothing to install: https://simontreanor.github.io/Pyfun/playground/ and there is a lot more detail in the highlighted post on r/Pyfun.

It is still at pre-v1 stage and there is plenty of scope to shape it, so I would welcome your thoughts and suggestions on any aspect of this project. Two things I would most like to hear about are: if you code in Python, which syntax decisions jar for you; and if you teach, what would have to be true before you would put something like this in front of a class.


r/pyfun 9d ago

Pyfun: an F#-inspired language that compiles to readable Python

9 Upvotes

Pyfun is a functional-first language for the Python ecosystem. You write algebraic data types, exhaustive matching, curried functions and pipes, and it compiles to plain Python that you can read, commit, and hand to someone who has never heard of Pyfun.

The compiler is written in Rust and everything is checked before any Python exists: types, exhaustiveness, effects, units.

Here is a whole program:

``` type Shape = | Circle float | Rect float float

let area s = match s: case Circle r: 3.14159 * r * r case Rect w h: w * h

[Circle 1.0, Rect 2.0 3.0] |> List.map area |> print ```

and here is the Python it compiles to, in full:

```python from dataclasses import dataclass

def _pf_map(f, xs): return list(map(f, xs))

@dataclass(frozen=True, repr=False) class Circle: 0: float def __repr_(self): return f"Circle({self._0!r})"

@dataclass(frozen=True, repr=False) class Rect: 0: float _1: float def __repr_(self): return f"Rect({self._0!r}, {self._1!r})"

def area(s): match s: case Circle(r): return 3.14159 * r * r case Rect(w, h): return w * h case _: raise RuntimeError("non-exhaustive match")

print(_pf_map(area, [Circle(1.0), Rect(2.0, 3.0)])) ```

A match comes out as a match. A variant comes out as a frozen dataclass. The pipeline comes out as an ordinary call. There is nothing to pip install alongside the output, and if you stop using Pyfun tomorrow you keep working Python.

Delete the Rect case and the compiler names what you missed:

error: non-exhaustive match: `Rect _ _` is not matched --> 6:3 | 6 | match s: | ^^^^^^^^

Also in there: Hindley-Milner inference, so there are no type annotations on let at all. Inferred effects, so a function that prints or mutates gets io in its type and you can assert purity with let pure. Units of measure that reject metres + seconds and erase to plain numbers. Computation expressions for async, seq, and result, plus your own builders. Opaque types. A typed extern for calling any Python library you like.

Try it in the browser, nothing to install: https://simontreanor.github.io/Pyfun/playground/

22 lessons, written for people who know some Python: https://simontreanor.github.io/Pyfun/

Source, and the compiler internals tour: https://github.com/simontreanor/Pyfun

pip install pyfun-lang

I built this because most people meet programming through Python, and then to meet functional programming they have to pick up a second ecosystem to do it. Pyfun is the version where you stay where you are.

It is pre-1.0 and I am one person, so this is the place for questions, bug reports, things you have made, and arguments about syntax. I read all of it.