metazip / pointfrip

pointfree interpreter with instance variables and classes, in lazarus
6 stars 1 forks source link

Please add documentation and a tutorial in English #1

Open OlegAlexander opened 2 years ago

OlegAlexander commented 2 years ago

Dear @metazip, thank you for creating Pointfrip! Could you please add more documentation and a getting started tutorial in English? I can see that the reference PDF is in English but the other documents are in German. Thank you!

metazip commented 2 years ago

I started with an attempt at the getting started tutorial

OlegAlexander commented 2 years ago

Thank you, that's very helpful!

OlegAlexander commented 2 years ago

The first thing I did was redefine . == ° so it's easier to type in the composition operator. And now the example becomes:

sum . ((id * id) aa) . iota . 10
385

Hopefully the . isn't already bound to something else :)

Edit: And now I see in the reference pdf that I can just use the letter o for composition. Never mind!

metazip commented 2 years ago

Partial conversion of quickinfo.pdf to English.

metazip commented 2 years ago

Is the ° circle symbol hard to reach on English keyboard?

OlegAlexander commented 2 years ago

Yes, the ° symbol is not available on the US keyboard. I've been copying and pasting it from your code examples.

metazip commented 2 years ago

Partial conversion of document.pdf to English. And a few English additions in reference.pdf.

metazip commented 2 years ago

the "loop fusion" example of https://twitter.com/TheOlegarchy/status/1533976236732522498 looks like

avgb == / ° fold ° 'sumLength, (0;0;), id,    //   ([0] / [1])   =   / ° [0],[1],

// sumLength ° (sumAcc,lenAcc,),x,
sumLength == ([1]+[0]°[0]),(1+[1]°[0]),

// fold ° 'expr,initdata,list,
fold == (isatom°[2]) -> [1] ; fold ° [0],([0] app [1] ee head°[2]),(tail°[2]),

in PF

OlegAlexander commented 2 years ago

Awesome! Thanks! I just tried it. It's nice to see a more advanced PF example like this.

I was going to ask you, does PF have where clauses like the FL spec? See section 5. https://theory.stanford.edu/~aiken/publications/trs/RJ7100.pdf image

metazip commented 2 years ago

Thanks for the hint. Unfortunately, there is no syntactic where clause in Pointfrip. To use local identifiers there are tables/dicts in Pointfrip. With this one could try to build something like clauses. Maybe like this:

((#f app 1,2,3,)+(#g app 1,2,3,)) ° (f:='(head°tail)) ° (g:='(head°tail°tail))

But there is no cyclic reference to other definitions. Pointfrip only works with instance variables. So it is free of lambda variables as in wikipedia. Backus initially spoke out against lambda variables, as here, but then introduced them to FL in order to be able to add new functional forms. The definition of new functional forms also worked in Pointfrip without lambda variables. What do you think, can one do without lambda variables or not?

OlegAlexander commented 2 years ago

My understanding is that as long as the language has a sufficient number of combinators and allows recursion, then lambda variables are not necessary. There is a good article about concatenative languages. Read the section called The Dark Side for an example of when you might want lambdas. I believe the Factor language has lambdas but they are rarely used. I don't think PF needs lambdas.

But the where clause would be nice because it allows you to nest definitions. This is useful for two reasons. First, it allows you to reuse def names. Second, and more importantly, a program using where clauses has less surface area. That is, when defs can be nested, the reader has more local context about where a def is used. In long point-free programs, this can be a big boost to readability.

metazip commented 2 years ago

But the where clause would be nice because it allows you to nest definitions. This is useful for two reasons. First, it allows you to reuse def names. Second, and more importantly, a program using where clauses has less surface area. That is, when defs can be nested, the reader has more local context about where a def is used. In long point-free programs, this can be a big boost to readability.

You're right.

Since Pointfrip is a hybrid, one could use classes for the programming at large. I mean for reusing def names:

main ° (prog :: 1;2;3;) // the prog object

f == [f] fn fail
g == [g] fn fail
inc == [inc] fn fail
sqr == [sqr] fn fail
main == [main] fn fail

prog == .. { list // the prog class
[f] == g ° tail
[g] == head dip
[inc] == (id + 1) dip
[sqr] == (id * id) dip
[main] == sqr ° inc ° f 
}

The names f to main for the selectors can then also be used for other classes.

metazip commented 2 years ago

Should I take a leave of absence from Google?

OlegAlexander commented 2 years ago

I don't understand the question. Do you work at Google? Could you elaborate?

metazip commented 2 years ago

Maybe the English wording sounds a bit strange because I used google translate to translate from German to English.

OlegAlexander commented 2 years ago

Yes, that's what I thought :)

metazip commented 2 years ago

What do you think about this quote?

OlegAlexander commented 2 years ago

I think this quote is taken out of context. The full interview PDF is here and the video is here. It's hard to say exactly why Backus thought his work was ultimately unsuccessful because he didn't go into much detail. My guess is that he meant he couldn't get IO to work or that he couldn't model time with expressions.

metazip commented 2 years ago

I'm amazed at how deep you've delved into this topic. I could learn something from you.

metazip commented 2 years ago

With the interesting links you could create a great collection of links, for example.

OlegAlexander commented 2 years ago

That is a great list! The "Function Level Programming and the FL Language" video is one of my favorites. Here are a few more links. The Algebraic Programming material is very hard for me, but hopefully one day I'll be able to fully understand it :)

Algebraic Programming

Code Golf languages (many of which are stack-based and/or point-free)

Array Languages (which support point-free style)

Libraries that support point-free style

metazip commented 2 years ago

The Algebraic Programming material is very hard for me, but hopefully one day I'll be able to fully understand it

John Backus wanted to fight the complexity, example

metazip commented 2 years ago

Can a GitHub member save the modified README text?

OlegAlexander commented 2 years ago

I just tried to modify the README directly but it didn't work. It wanted me to create a pull request. Maybe giving members direct edit permission is a paid feature? Not sure.

metazip commented 2 years ago

Try that again.

OlegAlexander commented 2 years ago

Yes, it works now! Thank you!

metazip commented 2 years ago

I just watched part of the FL video. Why didn't this man get an engineering chance for his FL?

OlegAlexander commented 2 years ago

Sorry, what do you mean by "engineering chance"?

metazip commented 2 years ago

He wanted to make programming with FL an engineering discipline. (min. 9:00)

metazip commented 2 years ago

I thought about my own technique for side effects, but found out later that it is the monadic technique. I then extended them with algebraic effects in the class-oriented way (io-driver). With the continuations >> it looks like a pipeline. it then always returns the effect result. It passes the instance variables through every continuation.

((#draco loadtext)°(draco:=corepath & "drache.pf") eff 'io)>>(it showinfo)>>(#draco run)>>()

If the example doesn't run, you can also use "drache.txt". (I may have made a mistake with the monad stack because there is no word return.)

OlegAlexander commented 2 years ago

I thought the IO monad was only needed in a lazy evaluation language, where the monad is used to force the order of evaluation. In a strict (eager) evaluation language the IO monad isn't necessary. Is PF strict or lazy by default?

metazip commented 2 years ago

So that these rules and laws can also be used in IT - this is the reason for the use of FP - referential transparency must be maintained. No side effects may occur within the referential transparency. For a side effect to happen, a break or termination must occur. A monad is a termination given a continuation, which also results in sequencing. Pointfrip doesn't have a lazy evaluation, but I tried it with this one.

metazip commented 2 years ago

To the mission, a stack language like Joy is very flexible, but tends towards obfuscation (last point) and has problematic exception handling because of the stack.

metazip commented 1 year ago

I found this on Twitter: Wrath What do you think, is programming with lambdas better or without? (LtU Comment)

OlegAlexander commented 1 year ago

My conclusion is that programming with lambdas is better. The point free style sometimes works in higher order functions, but should not be used at the top level.

metazip commented 1 year ago

Should one only recommend the film or should the Pointfrip archive continue to exist so that Backus FP interested parties can gain experience with a 100% point-free style in order to be able to understand the failure. So that this development of the PF interpreter is not repeated. ?

OlegAlexander commented 1 year ago

Of course, the Pointfrip archive should continue to exist! Do you agree with my conclusion that a 100% point-free style is not a viable way to write programs? And that it can never be made viable, even with the "right" combinators, like construction?

metazip commented 1 year ago

Do you agree with my conclusion that a 100% point-free style is not a viable way to write programs? And that it can never be made viable, even with the "right" combinators, like construction?

Unfortunately, I lack the right feeling and experience for this. I think the point behind PF and FP is that you can rearrange* equations like you do in math. Whether lambdas are a hindrance for the purpose is just speculation for me. Should be examined more closely.

Others have had problems with Backus' suggestion too, like here. But it was mentioned that the creators of Haskell are smart people and they use lambdas.

(*) Example from POPL, rules like that: α (f ° g) = (α f) ° (α g)

OlegAlexander commented 1 year ago

Originally I thought the same thing--that point-free code is ideal for algebraic reasoning and that lambdas somehow interfere with this. But later I realized that algebraic reasoning could be done with lambda also. In fact, you can gradually eliminate one arg at a time with manual eta-reduction. I love this stack overflow answer by Jon Purdy where he recommends a partially point-free style: https://stackoverflow.com/a/47042937/3512820

metazip commented 1 year ago

Is working with Pointfrip a madness?

OlegAlexander commented 1 year ago

Honestly, I haven't done that much coding in Pointfrip specifically. But theoretically, any 100% point-free or concatenative or stack-based language is hard to program in, even with a lot of practice.

metazip commented 1 year ago

Without wanting to influence you, Backus has also experimented with lambdas. The script has been available for free for the last few months: Function Level Programs as Mathematical Objects

Summary PFO1 PFO2

OlegAlexander commented 1 year ago

Nice paper! Haven't read that one before. He mentions that in Lisp programming with lambdas usually has more than one parameter. However, in OCaml/F#/Haskell all functions are curried by default which means that let add x y = x + y is just syntax sugar for let add = fun x -> fun y -> (+) x y and this can be eta-reduced to let add = (+). Currying satisfies his requirement that every function takes only a single parameter and makes it possible to do equational reasoning even in the presence of lambdas.

However, my disenchantment with the point-free style is not about lambdas vs no lambdas. It's about brevity and clarity. I originally thought that if a little bit of point-free style is shorter and clearer then more point-free style would be even shorter and even clearer. However, it turned out that point-free style is like salt--to be used only in moderation.

No matter how hard I tried--and you know I tried very hard--I kept running into examples where the point-free style was longer and less readable than the pointful style. The basic problem is that the point-free style is inherently stack-like, so any time the data flow becomes even a little bit non-linear--where a computed value needs to be used in several places later--the code becomes very hard to read and write, even with the "right" combinators from Backus!

I realized I was wasting my time trying to "be the compiler"--the compiler already turns pointful code into stack commands for me and makes many optimizations on top of that. The benefits of algebraic reasoning promised by the point-free style do not outweigh the difficulties of trying to "be the compiler".

So you see, my conclusion is a practical one--the point-free style is good in moderation, like salt. And it doesn't mean I have any less respect for John Backus!

metazip commented 1 year ago

Idea of a restricted where-clause. If you define the following where combinator:

where == (top°term) app prop°arg,'_it,(top°pop°term),

You could then design this working function that way:

addsqinc == (it + #square app #inc app it)
            where (  (id*id) square
                     (id+1) inc  )

You would have to change the syntax for the parenthesis and then you would have this picture:

addsqinc == (it + #square app #inc app it)
            where (  square == id*id
                     inc == id+1  )

But it is only an idea for a restricted clause. You can't do recursion and other things. And it would be limited to just using the instance variables.