The Design Of F (A Small Functional Language)
ac1235.github.io/f.htmlPosted Sep 28, 2018, 3:57 PM UTC
Posted Sep 28, 2018, 3:57 PM UTC
I am currently starting to implement this and have a few questions:
For convenience, this introduction assumes literal syntax for lists (
{a b c}), strings ("hello world"), and numbers (12.3)
Is that syntax not fixed? Could/Should that change?
Wow this is really cool! I am realy vague at plafes where the end decision doesn't add to the feel of the core language. Basically all these decisions are up to you.
Except for scoping perhaps which I should clarify: since all variables are immutable (:=) always creates a variable in the inner most block/function.
If you are still interested in what I'd do (not that you have to follow my advice):
+ - * / < > = <= >= <> with standard math precedence, although no user defined operators (things like mod could be written as a mod: b and infix function application has the lowest precedence)... to mean rest of the arguments in the text, so [|...| argList := {...}; doStuff ()] has the intended effect of creating an argument list (a bit like in Lua)I now have the implementation finished to a degree where I would like to now your opinion on it. It is still hosted on github. I would like to hear if you find any bugs. All your example should work as expected.
Wow that's great! I will try it out as soon as I can :)
Okay I tried it now and it's great! However I also had to install pydot, which the README did not mention. But the software is wonderful and I'm impressed how well it handles the obscure syntax of F.
I will definitely fork your repo soon and test a few of my design ideas in my version of it.
What I'd like to know is if you are interested in maintaining your implementation and doing things like adding a REPL or turning it into an AST compiler (kinda like Hy works) or stuff like that. In that case I'd love to see a lot of your own ideas implemented too and I will keep you up to date with what I intend for the future, but in either case thank you a lot for your awesome work :-)
I already have a first version uploaded as github. This is not finished (quite a few things missing or wrong), but I don't have any time to work on it for the next two weeks. (I may have time two answer issues) If you have questions ask.
This is really cool! And your code is very readable actually.
I am happy to hear that.
How are you running this? Neither python 2.7 nor 3.6 work for me.
I am using python3.7 because of the from __future__ import annotations. You can also remove this line, but then you may have to remove a few annotations. Also you need to install lark (pip install lark-parser)
Maybe i missed it, but how does the language determine the amount of arguments passed? What about fixity?
How would (+) 1 2 3 + 4 be parsed?
I believe as many arguments as possible are matched. Infix Operators have a higher priority then normal calls (hence the brackets around +).
You are right, all the arguments go to a function that can (a little bit like in shell scripts), but just like in ML function application has higher precedence than all operators, so sin x / cos x parses as (/) (sin x) (cos x).
that's about what i expected, v nice.
One other question, i assume there's no concept for composite types except the array right?
Well, there is no reason why you couldn't have maps, bags, sets and what not. I think an actual implementation should also provide maps at least.
That would mean that his example would be parsed as (+) ((+) 1 2 3) (4)? Then I misunderstood. I thought it would be parsed as ((+) 1 2 (+)(3 4))
Yes indeed
Honestly, what I see here is a perfectly fine and usable language. I'm not entirely clear on what do does, but otherwise, it makes me more excited about functional programming. It is really cool how such a simple syntax can allow for the implementations of so many imperative constructs.
do appears to just be a "call this function" function. It's first argument is a function, and it passes all the arguments after that to that function. It's just a more explicit way to write it that's recommended for calling functions passed as arguments, probably in part for type-safety reasons.
Except for the type safety part (I did not think about that, but you might be on to something) this is exactly what I intended.
As a consequence of that do can also be used to create a lexical scope: do [ a := b; c ]. This is roughly equivalent to the (function(){...})() pattern in old JS code.
Quite similar to the let construct in most Lisps, too:
(let [ a (+ b c) ]
...)
Slight tangent, but as much as I still use it from time to time when it's needed, I really hate that pattern in JS... It's just a really ugly syntax for a concept that should be a lot simpler. It's gotten nicer with arrow functions, but (() => {...})() is still pretty nasty to look at, especially when people sprinkle it throughout their entire codebase in the most unsavory places imaginable.
Yeah in JavaScript it really is ugly, but I think that's because of the syntax do [ stuff ] looks pretty elegant to me actually.
I like that your expression and block syntax is (at least roughly) the same.
Any particular reason for choosing "[" and "]" rather than "(" and ")"?
Also variadic functions seem nice but I don't know how they interact with a type system.
I only skimmed your write-up but what kind of type checking are you planning on?
Just to clarify I used the word block in the Smalltalk/Ruby meaning of the word. A block is a lambda is an anonymous function. I chose [] instead of {} because it looks more clean and is how other languages do it. Also if I chose curlies, I'd reassamble C enough that the differences would be confusing.
The language as it stands is dynamically typed.
Cool. Thanks (both for the clarification and explanation)
Hey little question: do you feel the same about languages too closely reassambling C? In my mind, if something looks like C, I think like in C. This is a littpe bit of an issue though when the language behaves completely differently.
Yeah, ideally things that look the same do the same thing.
E.g. i don't like pony's assignment operator (in "a=b" it evaluates to the old value of a, which a no longer holds).
Still. Some amount of breakages are necessary for progress, even if they cannot be introduced in some kind of clean/visually distinct manner.
I like the way if else works, it's very clever!
Don't sell yourself short! The language design is very cool, like syntax sugar for Scheme in a way.
Well I never said I'm not a good language designer, did I ;)
I'm just not good at implementing my ideas. That's not selling myself short, that's knowing where my strengths and weaknesses are.