Zulip Chat Archive
Stream: general
Topic: PSBP, a program specification based programming library
Luc Duponcheel (Jul 23 2025 at 21:49):
Hello Lean folks,
I am Luc Duponcheel, a Functional Programming veteran. I am new to this forum.
I have worked on Monads and Monad Transformers since the 90-ties (previous century) with researchers like Erik Meijer, Graham Hutton, Mark P. Jones, Doaitse Swierstra and others ... .
I am retired now.
I think of a (various) monads as specifications of effectful expressions.
But what are specifications of effectful functions?
Arrows are an appropriate candidate.
I consider, what I call programs as being an appropriate candidate (they are inspired by Backus's FP).
I have implemented a PSBP Scala and Haskell librariy using this idea.
PSBP stands for Program Specification Based Programing.
Recently I decided to also use Lean as a programming language because of its theorem proving capabilities.
Attached (PSBP.lean) you can find preliminary code with my idea's. In practice, PSBP defines a library level, specification based, programming language.
The code is really only the tip of a huge iceberg (no laws and proofs yet, no effects yet, and only 1 trivial active materialization). My Scala and Haskell code is much more elaborated.
I am wondering if I could start some library project to contribute to this community, and, of course, I am wondering if there are any enthusiasts willing to contribute to that project.
Finally, why considering programs (effectful function specifications) instead of computations (effectful expression specifications)? Well, just like functions, programs are denotational artifacts (they have a meaning), while, just like expressions, computations are operational artifacts. Just like functions can be defined using expressions, programs can be materialized using program implementations in terms of computations. I consider functions and programs as a "goal" and expressions and computations as a "means" to reach that goal.
Luc Duponcheel (Jul 23 2025 at 22:25):
By the way, I aleady have a first remark on the implementation of Applicative. It contains the following definition : seq : {α β : Type u} → f (α → β) → (Unit → f α) → f β. Ok, I understand that, because Lean evaluation is strict, type Unit → f α is used, but why not using Thunk (f α) in order to avoid multiple evaluations?
Shreyas Srinivas (Jul 23 2025 at 23:14):
Hi Luc, welcome to Lean. I am browsing through your file and in my initial skim, I notice that you could use the inbuilt Prod and Sum types instead of the ProductType and SumType definitions. They will save you a lot of time later when proving theorems. Another quibble. You could share code more easily on this zulip, either through a code block like so:
```
-- some lean code
```
or a github gist. You can make the codeblock collapsible by wrapping it as a spoiler
Shreyas Srinivas (Jul 23 2025 at 23:15):
This helps us in two ways. First we can copy and paste the code in our editor. Secondly, we can use a little icon on the top right corner of the code block to open it on the lean scratch pad online. You can see this in the example below. The icons appear when you hover the mouse on the code block
def example_code := 37
Shreyas Srinivas (Jul 23 2025 at 23:38):
Once my laptop finishes updating I will paste a more lean-style refactoring of your code. I think it should make it neater
Shreyas Srinivas (Jul 23 2025 at 23:38):
At a conceptual level, I see that you are using several typeclass instances again and again. You could also define mixin type classes to extract the common combinations into one typeclass
Shreyas Srinivas (Jul 24 2025 at 00:01):
Code listing
Shreyas Srinivas (Jul 24 2025 at 00:06):
- I have replaced
ProductTypewithProd. The notation forProd a bisa × b. The cross is in unicode and written with the shortcut\x. - I have replaced
SumTypewithSum. The notation forSum a bisa ⊕ b. In this case I have replaced all occurrences ofSumType a bwithThunk a ⊕ Thunk b - For every structure
structure XYZ, you can construct and destructure it asXYZ.mk <field 1> <field 2> .... There is standard notation for this⟨<field1>, <field2>,...⟩. The left and right arrow brackets are unicode characters respectively written using the shortcuts\<and\> - I have replaced all ascii arrows
->with unicode arrows→which can be entered using the shortcuts\->or\r - I have replaced all occurrences of
fun a => awithid - There was one occurrence of a function creating a product type object from its pieces which looked like
fun x y => {fst := x, snd := y}. I replaced it withProd.mkwhich does the same thing
Shreyas Srinivas (Jul 24 2025 at 00:33):
and finally, I have to ask one question : Why do you believe it will be easier to reason with Arrow computations over Monads (for which a system is already being tested in one of the release candidate toolchains)
Aaron Liu (Jul 24 2025 at 06:42):
Why thunks?
Luc Duponcheel (Jul 24 2025 at 08:33):
Shreyas Srinivas, thanks so much for your constructive comments. My main goal is to extend my "library level programming language" with extra monad-like features and to establish "program" laws and proof them making use of the corresponding monad laws (I am going to name the various combinations of my type classes "programs" i.e. effectful functions, just like computations (monads) are effectful expressions). Question: In Haskell there is an actor-like library (hakka) to deal with parallelism. I could use that library to add a "parallel product" and, for example, use it to write a parallelFibonacci. Does Lean also have such a library? FWIW, I am just beginning to learn how to write proofs, so do not expect things to proceed very quickly. All comments are welcome.
Shreyas Srinivas (Jul 24 2025 at 08:35):
I don’t think there is a Hakka style library for parallelism yet
Shreyas Srinivas (Jul 24 2025 at 08:38):
Cc : @Henrik Böving about parallelism
Luc Duponcheel (Jul 24 2025 at 08:39):
Aaron Liu, in
sum {a b c : Type u} : program c a → program b a → program (Thunk c ⊕ Thunk b)
only one of the two arguments of the resulting program are supposed to be used. Since, by default, Lean has eager evaluation, I use thunks to emulate lazy evaluation.
by the way, my question about the Applicative interface still remains in
seq : {α β : Type u} → f (α → β) → (Unit → f α) → f β
the (Unit → f α) does not really emulate lazy evaluation (evaluate zero times or one time), but rather "by name evaluation" (evaluate zero or more times). So I think that
seq : {α β : Type u} → f (α → β) → Thunk (f α) → f β
would be more efficient.
Shreyas Srinivas (Jul 24 2025 at 08:43):
you can get asynchrony using docs#Task
Henrik Böving (Jul 24 2025 at 08:43):
Shreyas Srinivas said:
Cc : Henrik Böving about parallelism
I work on async IO, not parallelism, these matters are disjoint for the most part.
Shreyas Srinivas (Jul 24 2025 at 08:43):
Arrows can also represent asynchrony iirc
Luc Duponcheel (Jul 24 2025 at 08:43):
Shreyas Srinivas can you help me a bit by sending me a private message and copy/paste your first reply into a file that you attach, so that I can see how you produced the collapsed inline code? thx
Shreyas Srinivas (Jul 24 2025 at 08:47):
I am currently on my phone so this will be difficult for now. But you can open the code in the lean4 playground. If you hover your mouse over the listing you will see two icons on the top right corner. Clicking on one of them will open the code in a lean editor on the web browser.
Aaron Liu (Jul 24 2025 at 08:49):
Luc Duponcheel said:
Aaron Liu, in
sum {a b c : Type u} : program c a → program b a → program (Thunk c ⊕ Thunk b)
only one of the two arguments of the resulting program are supposed to be used. Since, by default, Lean has eager evaluation, I use thunks to emulate lazy evaluation.
by the way, my question about the Applicative interface still remains in
seq : {α β : Type u} → f (α → β) → (Unit → f α) → f β
the (Unit → f α) does not really emulate lazy evaluation (evaluate zero times or one time), but rather "by name evaluation" (evaluate zero or more times). So I think that
seq : {α β : Type u} → f (α → β) → Thunk (f α) → f β
would be more efficient.
In a sum type, you only get one of the two? program is a function type, so those won't be evaluated until you feed them an argument. And the sum type Thunk c ⊕ Thunk b contains only one thunk in total, and you're forcing it immediately once you acquire it, so I don't see the point of thunks here.
Aaron Liu (Jul 24 2025 at 08:50):
It would be equivalent to just force the thunk at the call site I think
Luc Duponcheel (Jul 24 2025 at 09:03):
Shreyas Srinivas, about your final question,
1) short specific answer: Take the associativity law for computations (monads), for programs (btw, you called mine arrows, but they are slightly different) it boils down to
p ~~> (q ~~> r) = (p ~~> g) ~~> r which is so much simpler and intuitive than the corresponding computation law.
2) short general answer: embrace simplicity that is what abstraction is all about.
3) longer answer: computations (monads) are effectful expression specifications, programs are effectful function specifications. Programs and functions are denotational artifacts (they mean something and can be given a meaningful name). Computations and expressions are essentially operational artifacts. For example: can you give a meaningful name to 1 + 2*3 (of course 7 would be a reasonable answer, but you know what I mean). Finally, functions are defined in terms of expressions, likewise programs are defined in terms of computations (that is exactly what I did in my code). Writing programs is the goal using computations for doing so is a means to reach that goal.
Luc Duponcheel (Jul 24 2025 at 09:14):
Shreyas Srinivas, one final remark. I had to annotate my fibonacci and factorial code with unsafe. Fair enough that Lean does this termination check. But, as I wrote, fibonacci and factorial are not programs, they are program specifications (as can easily be derived by their signature, there are type class constraints involved). I can materialize them in various safe ways (I used Active but I could, e.g. have used Reactive as well, useful for parallelism). Think of a program specification as a (special) kind of program description. Compare this with the painting "Ceci n'est pas une pipe" painted by René Magritte (also from Belgium, just like me). It is a description of a pipe. Or think about a painting with an effect (an explosing bomb), well, luckily enough it is not an explosing bomb so it is not unsafe at all to hang it on your wall.
Shreyas Srinivas (Jul 24 2025 at 09:38):
If you have termination issues, then marking your code partial should do the trick. The issue here is not one of termination. Lean cannot prove that the type you have specified should be inhabited
Shreyas Srinivas (Jul 24 2025 at 09:40):
In particular, lean is not sure that program is a non-empty type in the first place.
Shreyas Srinivas (Jul 24 2025 at 09:41):
So what you need is a Nonempty instance. I added one to the factorial example and now it compiles:
partial def factorial
[∀ x y, Nonempty (program x y)]
[Functional program]
[Creational program]
[Sequential program]
[Conditional program]:
program Nat Nat :=
if_ isZero one $
else_ $
let_ (andThen minusOne factorial) $
in_ $
multiply
Shreyas Srinivas (Jul 24 2025 at 09:41):
but when you invoke it, you have to supply this nonempty instance
Shreyas Srinivas (Jul 24 2025 at 09:42):
But since you say you are interested in the theorem proving aspects, you should know that there is limited support for proving anything about partial defs
Shreyas Srinivas (Jul 24 2025 at 09:43):
The existing support goes through something called partial_fixpoint which is currently only supported for functions which return an Option value.
Luc Duponcheel (Jul 24 2025 at 10:16):
Shreyas Srinivas, you are my hero!
I will update my code, add operation symbols (for readability) and post everything using your instructions on how to do so in an appropriate way.
About the theorem proving aspects ... not really good news to hear about this.
Do you think that refactoring my code using partial_fixpoint and Option results is worth the trouble?
I can imagine that those fixed points are akin to catamorphisms (I used them in the 90-ties when I worked in Utrecht with the group of Erik Meijer) but somewhat modified to yield an Option result in order to transform a partial function into a global one, right?
Luc Duponcheel (Jul 24 2025 at 10:46):
Thanks for all the constructive remarks.
I updated the code a little bit (I also added a few operation symbols for readability). For now I still use the unsafe keyword. The partial fixed point stuff is for later.
For those who read the factorial definition and wonder what is happening behind the scenes. let_ ... in_ ... creates (Creational) an intermediate local value that, together with the recursive call of minusOne >=> factorial can be used by multiply.
Operationally, instead of popping an argument from the stack and pushing a result on the stack (what happens with sequential composition (Sequential) >>>), it keeps the argument on the stack and pushes the result on top of it on the stack.
My library level programming language is pointfree (cfr. Backus FP), but it can also deal with effects (internal, e.g. state, and external, e.g. IO). The language can also be (and sometimes has to be) used positionally by accessing values on the stack above by position. This is typically necessary for simple sequential main-like programs (think of them as recipes) where, apart from initial ingredients, also intermediate produced ingredients need to be used. Note that the intermediate ingredients can, potentially, be produced by fully fledged programs (for example using recursion and condition (Conditional) to mix appropriate ingredients until they turn into "mayonnaise"). In other words, PSBP supports hybrid pointfree and positional programming. I hope that this analogy helps. Below is the code. Of course it is only the tip of a huge iceberg. My Haskell and Scala code is more elaborate.
Code listing
Robin Arnez (Jul 24 2025 at 11:12):
Luc Duponcheel schrieb:
seq : {α β : Type u} → f (α → β) → (Unit → f α) → f β
the (Unit → f α) does not really emulate lazy evaluation (evaluate zero times or one time), but rather "by name evaluation" (evaluate zero or more times). So I think that
seq : {α β : Type u} → f (α → β) → Thunk (f α) → f β
would be more efficient.
Using Thunk is unnecessary, for several reasons:
- The caller can ensure themselves that the functions only needs to evaluate once, in the sense of:
let x : Thunk (Option Nat) := ... -- computation that we *really* don't want to run twice
f <*> x.get -- i.e. seq f (fun _ => x.get)
- Usually, the implementation of
seqalready ensures that the function is only evaluated once - If not, the implementation can do:
instance : Applicative FunnyThing where
seq x f :=
let thunk := Thunk.mk f
-- use thunk.get later
- The definition of
seqwill usually be inlined and the compiler has better support for functions than forThunks
Robin Arnez (Jul 24 2025 at 11:13):
(deleted)
Robin Arnez (Jul 24 2025 at 11:26):
Here's also a cleaned up version
Code listing
I've adjusted the formatting and indentation, removed Thunk for the sum type (I think it's unnecessary..?) and replaced Active with Id which already exists in the core library.
Luc Duponcheel (Jul 24 2025 at 14:21):
Robin Arnez, just back from a cycling trip (I am also an addicted (race bicycle) cyclist and (green house) gardener), thanks so much for your constructive comments. What a positive community, this Lean community! In fact, with the standard Sum type the Thunk's are indeed not necessary. Gonna update my code.
Luc Duponcheel (Jul 24 2025 at 14:22):
Robin Arnez, by the way, which formatter do you use? Is it a command-line one? Can it be integrated with vscode?
Luc Duponcheel (Jul 24 2025 at 14:37):
Shreyas Srinivas, I was thinking (.. .while cycling on my race bicycle ...).
There are two things: programming and proving properties .
I want to do both.
But do I really want to prove properties of (potentially unsafe) programs?
Maybe not.
I want to prove properties of the type class members (such as associativity of program sequential composition using computation (monad) laws).
So, I am going to continue "living unsafe (in a disciplined way) and hoping for the best" and learn how to prove laws such as the associativity one mentioned above.
Shreyas Srinivas (Jul 24 2025 at 14:39):
You probably want to look at docs#LawfulMonad and docs#LawfulApplicative then. By imposing this typeclass constraint on your monad, you get the monad laws for free
Shreyas Srinivas (Jul 24 2025 at 14:41):
The distinction is made because it might be tedious to always prove that actual monads behave lawfully. For example the IO monad.
Shreyas Srinivas (Jul 24 2025 at 14:42):
Also you might want to check out the new (in beta essentially) monadic verification framework that attaches a program logic into monads. #general > new monadic program verification framework
Luc Duponcheel (Jul 24 2025 at 14:45):
Shreyas Srinivas, thanks for your tip. I have looked at those docs already, but, frankly, I am starting to learn about all those fantastic Lean proving capabilities. Stay in touch, please.
Robin Arnez (Jul 25 2025 at 10:07):
Luc Duponcheel schrieb:
I can imagine that those fixed points are akin to catamorphisms (I used them in the 90-ties when I worked in Utrecht with the group of Erik Meijer) but somewhat modified to yield an
Optionresult in order to transform a partial function into a global one, right?
I'm not sure about catamorphisms but the idea is the following: Lean is primarily a math language and as such objects behave like "math objects" so in particular there is no such thing as a "natural number that doesn't terminate". As such, a general purpose fixpoint can be proven incorrect because it would imply something like
def abc : Nat := abc + 1
could exist. However, this would imply abc = abc + 1 which is mathematically unsound. So there are several strategies to still allow for recursion:
- Recursion "by termination": If a function terminates, there isn't any "doesn't terminate" problem and everything works fine. Lean implements this as well-founded recursion which requires you to prove that your parameters "decrease" by some well-founded notion of less-than.
- Partial recursion: Compiles the recursion as normal but hides the body of the declaration for proofs. That means that you can write functions that recurse indefinitely but can't prove anything about them.
- Recursion by monotonicity (
partial_fixpoint): This one uses a fact from order theory that in certain orders, all monotone functions have a fixpoint. Here you can work with anOptiontype that means something like:noneif it doesn't terminate andsome xif it does terminate and returnsx. In the kind of orders you're going to work with,x <= ymeans something like "if it terminated for some input inx, it will terminate with the same result iny". Then, in order to get the fixpoint of a functionf, you need to prove monotonicity offwhich amounts to proving that if fromxtoynothing changed that terminated before, then in the result, fromf xtof yalso nothing changed that terminated before.
Luc Duponcheel (Jul 25 2025 at 12:11):
Robin Arnez, thanks again for your information.
Catamorphism is +/- just a fancy word for structural recursion, and corresponds more or less to what you explained in 3. , see Catamorphism.
By that way, wiki page mentions the original https://maartenfokkinga.github.io/utwente/mmf91m.pdf paper (Erik Meijer is one of the authors). The paper was written a year before I joined the team for a short time.
Anway, I am first going to concentrate on programming and only proving laws of my type classes, e.g. associativity, in terms of the Functor, Applicative and Monad laws (in other words, not on any laws of programs written using my library level programming language (using the members of my type classes)).
I am also going to start a GitHub project.
I guess that if you wrote "math object" you meant "constructive math object". Using the "axiom of choice" (infinite product of non-empty sets is non-empty) there exist math objects that cannot be constructed.
Luc Duponcheel (Jul 25 2025 at 12:17):
Robin Arnez, by the way, which code formatter do you use? Is there a command-line one? Is there one that can be integrated with vscode? Sorry for repeating the question.
Patrick Massot (Jul 25 2025 at 14:37):
There is no automatic code formatter for Lean. This has been discussed many times, you can search on this Zulip. The short story is that the syntax extensibility of Lean makes it a lot harder than for regular programming languages. It will come at some point, but this is a lot more work than you would think.
Luc Duponcheel (Jul 25 2025 at 14:39):
Patrick Massot, frankly I am the kind of person who admires the
people building projects like Lean rather than underestimating their work :+1: .
Patrick Massot (Jul 25 2025 at 14:54):
I’m sorry, my message was probably unclear. My intend was not at all to complain about anything you wrote. Asking for a code formatter is a very natural thing to do those days. We very much understand why people can expect this. I simply tried to explain why it’s not there yet.
Patrick Massot (Jul 25 2025 at 14:55):
And I apologize if you felt I was accusing you of underestimating the work of people building Lean and its tooling.
Arthur Paulino (Jul 25 2025 at 15:01):
I'm particularly excited for the big shake up diffs on Lean 4 repos when the formatter come out :eyes:
Luc Duponcheel (Jul 25 2025 at 16:51):
Folks, I just created a new (preliminary) GitHub project,
https://github.com/LucDuponcheelAtGitHub/LeanPSBP.
Those who are inclined may also be interested in
https://github.com/LucDuponcheelAtGitHub/yoneda (code is Scala, docs are LaTeX)
and those who are interested in "understanding a universe framework by programming it" may also be interested in
https://github.com/LucDuponcheelAtGitHub/timeHybrids.
The "Time Hybrids" book, by Fred Van Oystaeyen, explains an algebraic geometry instead of analytic geometry based approach to the "universe". Fred has an, i.m.h.o. , highly underestimated mathematician's vision on reality.
... sorry for doing free advertising ...
Luc Duponcheel (Jul 28 2025 at 12:36):
Hello, I am trying to document my code in a similar way as the FPIL and TPIL documentation. So I downloaded the FPIL GitHub source, and, as a experiment, tried to add an extra section on PSBP. So far so good, but I encountered a strange error with anchors. So far I defined three anchors, Functional, Identity and Functorial in Examples, and used them in FPLean. Strangely enough everything worked out fine for the first two anchors but for the third one I get the following error
Code listing
The documentation fragments are
Code listing
and
Code listing
Luc Duponcheel (Jul 28 2025 at 12:43):
sorry folks the triple backquotes in my code are sitting in the way of properly showing the last code (any hints?)
Shreyas Srinivas (Jul 28 2025 at 12:46):
Verso is fairly new and doesn't have too many references to learn from. I'd recommend checking with @David Thrane Christiansen (CC)
Luc Duponcheel (Jul 28 2025 at 12:46):
Shreyas Srinivas, will do!
Luc Duponcheel (Jul 28 2025 at 14:58):
Hello, what a fantastic community, @David Thrane Christiansen helped me out !!!
Luc Duponcheel (Jul 29 2025 at 14:15):
Hello folks,
I pushed a first (preliminary) version of the documentation of the PSBP library to psbpDocumentation.
As usual you can make a local multi-html version (see README.md).
I also updated the PSBP library itself to use more Greek letters.
All comments are welcome
Luc Duponcheel (Jul 30 2025 at 19:51):
Hello,
First some context
My PSBP library can be seen as a library level pointfree programming language.
So I have, for example, defined library level keywords let_, in_, if_ and else_.
PSBP can also (and sometimes has to) be used as a positional programming language,
accessing values on a runtime stack by position. Especially for sequential
"recipe-like" scripts, accessing products of the initial and/or intermediate values
on the runtime stack. That being said ...
Here is my technical question
I am translating my Haskell code to Lean, more precisely my code for yet another
library level keyword at_ to access products of the initial and/or intermediate values
on the runtime stack. The code of at_ is below (lines 76 to 88).
You can also search for at_.
The intention is to also define a convenient operation symbol, but that's another matter.
Code listing
Similar (almost identical) Haskell code compiles fine.
You can run it the usual way using the little icon on
the top right corner of the code block to open it in
the lean scratch pad online.
Code listing
Aaron Liu (Jul 30 2025 at 19:57):
You want
λ αpβ σpα =>
let_ (σpα >=> αpβ)
Aaron Liu (Jul 30 2025 at 19:57):
functions bind their arguments very very tightly
Luc Duponcheel (Jul 30 2025 at 20:02):
Aaron, sorry copy/paste error (btw, see code above it with a normal language level let).
With your suggestion (and the code above) I still have an error
Code listing
even more confusing for me, here is the corrected code
Code listing
Aaron Liu (Jul 30 2025 at 20:04):
that means you need to be more explicit with your universes
Luc Duponcheel (Jul 30 2025 at 20:07):
Ok, I'll give it a try, all suggestions are welcome.
Patrick Massot (Jul 30 2025 at 20:16):
The suggestion is to replace all those Type u and Type v with Type and forget about universes.
Patrick Massot (Jul 30 2025 at 20:17):
I’m pretty sure you Haskell code doesn’t have universes.
Patrick Massot (Jul 30 2025 at 20:17):
And note most of Lean 4 programming infrastructure is Type only.
Patrick Massot (Jul 30 2025 at 20:18):
You can help Lean by putting variable {program : Type u → Type u → Type v} {α β γ σ : Type u} around line 38.
Patrick Massot (Jul 30 2025 at 20:19):
But you will immediately see that your if_ is already not doing what you want.
Patrick Massot (Jul 30 2025 at 20:19):
Since Bool only lives in Type and you want program : Type u → Type u → Type v.
Luc Duponcheel (Jul 30 2025 at 20:22):
It does not have universes indeed. I copy/pated from Monad and friends where there is also a : Type (max (u+1) v) which I already tried. and I also tried
Code listing
did not work.
I'll try with variable ...
Luc Duponcheel (Jul 30 2025 at 20:29):
Should I also somewhere use something similar to : Type (max (u+1) v) in my def of at_? I do not know the syntax for def's (I know the syntax for classes, cfr. Monad and friends) ... . My aim is to also state and prove laws, so I guess that the universes will eventually be necessary anyway (or not?)
.
Luc Duponcheel (Jul 30 2025 at 20:31):
btw, the α stands for "stack", and σ × β means β pushed onto σ.
Luc Duponcheel (Jul 30 2025 at 20:36):
Patrick, your suggestion to only use Type did the trick. But are you sure I'll never need the Type u and Type v like done in the Prelude.lean with Monad and friends (I mean, when doing theorem proving of my laws in terms of the laws of Monad and friends)?
Patrick Massot (Jul 30 2025 at 20:43):
All the monads that are used when programming in Lean are Type only.
Patrick Massot (Jul 30 2025 at 20:44):
It starts with docs#IO
Luc Duponcheel (Jul 30 2025 at 20:47):
Patrick, fair enough, but why then all those universes in Prelude.lean?
btw, what precisely starts at docs#IO?
Code listing
Patrick Massot (Jul 30 2025 at 21:00):
Monads also play a role in maths, not only programming. I guess this is why they have universes. What I had in mind with IO all the monads that are used in meta-programming in Lean. They are all built on top of IO using monad transformers.
Patrick Massot (Jul 30 2025 at 21:01):
Anyway, maybe I wrote too much. My recommendation is to at least start without all those universes. There is enough to do without worrying about universes.
Luc Duponcheel (Jul 30 2025 at 21:08):
Thanks so much for your suggestion.
Just like with my documentation, I'll start "lazily" simple and, maybe, later, add complexity by need. About IO... When programming PSBP in Haskell I used MonadIO a lot in order to use my "library level" programs together with IO. Especially for the logging of my parallel operator, used in a parallel version of fibonacci(implemented using hakka, an Actor library for Haskell). I would like to implement something like hakka in Lean as well.
But there are ony 24 hours in a day :grinning: .
Luc Duponcheel (Jul 31 2025 at 08:52):
Folks,
Thanks for all constructive replies.
I could get rid of the error, even without giving up the
{σ α β γ : Type u}
and
(program : Type u → Type u → Type v) : Type (max (u+1) v)
"universe mumbo-jumbo" by defining
a class Positional
and
an instance ... Positional where ...
It is all a bit "trial and error" for me, but, from a semantic point
of view, this class + instance approach actually makes sense.
I hope now that my examples will work as well
Code listing
Luc Duponcheel (Aug 02 2025 at 19:51):
Folks,
I added positional programming and stateful programming and updated the documentation. The documentation will, eventually, become a "github.io"
web page, but I am still struggling a with how to configure everything.
see
https://github.com/LucDuponcheelAtGitHub/PSBP
and
https://github.com/LucDuponcheelAtGitHub/psbpDocumentation
For now, for the documentation, you'll have to
- download the .zip file and unzip it,
- [optionally] run "$ lake exe psbpDocumentation --output _out/html --depth 2"
- look at the documentation locally as "htm-multi" of "html-single".
For example, on my laptop,
file:///home/luc/GitHub/Lean/psbpDocumentation/_out/html/html-multi/index.html
I am truly sorry.
Of course everything is preliminary work, but all comments are welcome.
Luc Duponcheel (Aug 04 2025 at 22:02):
I added programming with failure and it's documentation.
The situation now is
- Warning
- Introduction
- The PSBP Library type classes
- fibonacci and factorial
- What about Functorial?
- Computation Valued Functions
- ActiveProgram
- ReactiveProgram
- Positional Programming
- Programming With State
- Programming With Failure
Of course everything is preliminary work, but all comments are welcome.
I hope you folks do not consider this as "spam".
Luc Duponcheel (Aug 07 2025 at 14:26):
Hello folks, I updated programming with failure and it's documentation and added a section on validating failure, accumulating failures (Applicative based implementation) as opposed to the already existing section on fail-fast failure, only considering first failure, (Monad based implementation).
The (slightly changed) situation is now
- Warning
- Introduction
- The PSBP Library type classes
- fibonacci and factorial
- Computation Valued Functions
- ActiveProgram
- ReactiveProgram
- Positional Programming
- Programming With State
- Programming With Failure
Sorry for all my posts, hopefully the set of interested people is not empty.
And, once again, all comments are welcome.
For now I am going to (temporarily) stop adding extra programming features
and concentrate on defining appropriate "program and friends" related laws, and prove "program and friends" related theorems in terms of "monad and friends" related laws.
But I am still learning the (exiting(!)) theorem proving part of Lean (the very reason for me to switch from Haskell to Lean).
Thanks for reading.
Luc Duponcheel (Aug 25 2025 at 15:26):
Hello, folks, I added an introduction and added laws and proofs.
The content is now
- About
- Naming conventions
- Programs versus Computations
- The PSBP library type classes
- fibonacci and factorial
- Laws
- Computation Valued Functions
- Theorems
- ActiveProgram
- ReactiveProgram
- Positional Programming
- Programming With State
- Programming With Failure
Once again, sorry for all my posts, hopefully the set of interested people is not empty. And, once again, all comments are welcome.
Luc Duponcheel (Sep 04 2025 at 13:53):
Hello folks, I decided to document the PSBP library in the README.md file of the PSBP repository itself. Agreed, a bit more "low profile" than other Lean documentation. The documentation is also a kind of course with exercises and solutions.
Once again, sorry for all my posts, hopefully the set of interested people is not empty. And, once again, all comments are welcome.
Last updated: Dec 20 2025 at 21:32 UTC