By fixing some mistakes I've made, I can go forward.
I think I'm able to eliminate the def and have a working evaluation/call system.
Let's say, we can have symbols and lists of symbols only. Symbols can be bound to another symbol or list.
For number and integer, the arithmetic functions work on the symbols as if they were number or integer. I don't see any problem in that, ie. lambda calculus.
Also, let the previous scope system.
Evaluation. An evaluation of a symbol gives its bound symbol or list.
If one evaluates a list, it's a call.
And now, the calls.
We can call everything. A call on a symbol bind the symbol to the following argument or to a list of the following arguments. If the symbol hasn't been called before in the current scope, it is defining a new symbol on the scope.
And if one call a list, it's a function call.
So the previous code looks like this now:
('y '2)
{
('x '1)
('MyFn '((pr x) (pr y)))
(MyFn)
{
('x '10) ;no problem in this anymore
('y '3.14)
(MyFn)
}
(MyFn)
}
> 1
> 2
> 10
> 3.14
> 10
> 2
What we can see now is that, everything ends up with a '.
That's why I would like to explore the opposite strategy, an ' in front of what I want to evaluate.
It gives:
(y 2)
{
(x 1)
('pr x)
(MyFn (('pr 'x) ('pr 'y)))
('MyFn)
{
(x 10)
(y 3.14)
('MyFn)
}
('MyFn)
}
> x
> 1
> 2
> 10
> 3.14
> 10
> 2
I would like to put a star (like in C) instead of a ' for evaluation but I didn't succeeded.
That's a lot like PicoLisp. In PicoLisp, functions are just lists:
: (de foo (X Y) # Define the function 'foo'
(* (+ X Y) (+ X Y)) )
-> foo
: (foo 2 3) # Call the function 'foo'
-> 25
: foo # Get the VAL of the symbol 'foo'
-> ((X Y) (* (+ X Y) (+ X Y)))
Unfortunately, this approach means not having lexical scope. If any function has a parameter named * or + and it calls foo, foo's behavior might be surprising. Worse, you can't use lambdas to encapsulate state! (Or other context...)
With dynamic scope, you might as well define every function at the top level; local function syntax is only useful for code organization.
In some cases, dynamic scope can be useful for certain variables (typically configuration variables), but it's actually very easy to simulate dynamic scope in a non-concurrent program; just change a global variable and reset it afterwards.
---
"I would like to put a star (like in C) instead of a ' for evaluation but I didn't succeeded."
>> That's a lot like PicoLisp. In PicoLisp, functions are just lists:
Functions are lists of instructions/operations you can call and re-call. In every languages of the world. - meaning there is no reason they are treaten in a special case or with a special type.
The true concept is the call.
>> Unfortunately, this approach means not having lexical scope. If any function has a parameter named or + and it calls foo, foo's behavior might be surprising.
That's about bad programming. Just know what you're doing.
>> Worse, you can't use lambdas to encapsulate state! (Or other context...)
I gonna look at those lambdas. Thx
>> With dynamic scope, you might as well define every function at the top level; local function syntax is only useful for code organization.
That's not a question of code organization. That is a question of sense. If you define your functions at the top level because you can do it, you'll need a debugguer and a default scope system based on lexical scope. Beleive me :)
So with dynamic scope, you just have a functions system which plays its role: the possibility to repeat code. And a macro system which plays its role: the possibility to - over - tweak the source text in a way which has nothing to do with programming in itself. Functions and macros should be orthogonal concepts. That's the meaning of a concept: something which is orthogonal to every other concepts in the system.
>> In some cases, dynamic scope can be useful for certain variables (typically configuration variables), but it's actually very easy to simulate dynamic scope in a non-concurrent program; just change a global variable and reset it afterwards.
The fact that Object Oriented programming exists tell you re wrong here.
>> That's because asterisks ( ) create italics on this forum*
"Functions are lists of instructions/operations you can call and re-call. In every languages of the world."
I'm going to nitpick your use of "list" there. There's no reason effects need to be short actions in sequence. We might want to apply effects continuously, in parallel, in combination, in reverse, under supervised control, or distributed on machines under multiple people's (sometimes untrustworthy) administration. I doubt there's one definition of "effect" that will satisfy everyone, but that doesn't mean we should settle for the same old imperative effects in every single language. :)
I'm also going to nitpick the premise that a function is something "you can call and re-call." It can be useful to write a function that you only call once... if you intend to define it more than once. And sometimes it's useful to enforce that a function that can only be invoked once, perhaps for security; languages can potentially help us express properties like that.
---
"That's about bad programming. Just know what you're doing."
If I write a library with (de foo (X Y) (* (+ X Y) (+ X Y))) in it, would you say I should document the fact that it isn't compatible with programs that use + and * as local variables? Fair enough.
However, suppose we were given a language that had foo in it, and it behaved strangely whenever we used + or * as a local variable. Outrageous! That's a "hard coded pseudo-concept"! :-p We should ditch that language and build a new one with more consistent and orthogonal principles.
Alas, that language is exactly what we're using as soon as we define (de foo (X Y) (* (+ X Y) (+ X Y))).
---
"If you define your functions at the top level because you can do it, you'll need a debugguer and a default scope system based on lexical scope."
No need for a debugger if you're a good programmer, right? :-p And I'm not sure what you mean by needing lexical scope, since we're assuming that we've given up lexical scope already.
But I forgot, one downside to defining functions at the top level is that you need to give them names (global names). Maybe this is related to what you mean.
---
"Functions and macros should be orthogonal concepts."
Who's saying otherwise?
---
"The fact that Object Oriented programming exists tell you re wrong here."
The fact that OO exists is irrelevant. My point is that Arc's global scope is enough to achieve dynamic scope in a non-concurrent program. Who cares what other languages do?
(Incidentally, most popular OO languages also have global scope--static fields--which allows exactly the same kind of dynamic scope technique.)
I'm a little lost :) Are you in favor of lexical scope or against it?
The argument that lexical scopes are entangled with our notion of functions, so let's drop them since they're not an orthogonal concept -- that seems internally consistent and worth thinking about.
Oh sorry if I've not been clear: I'm in favor of dynamic scope :)
>> The argument that lexical scopes are entangled with our notion of functions, so let's drop them since they're not an orthogonal concept
Exactly. In the fun exploration of an ultimate language for good programming, name conflicts should not drive the language design at all.
Programmers should manage their name spaces with care. Also, having a tool for this, like namespaces, is not a problem. Seems even pretty good and it fixes everything.
"Programmers should manage their namespaces with care."
Totally. I think I'm closer to your point of view than anybody here (http://arclanguage.org/item?id=15587, footnote 1; http://arclanguage.org/item?id=12777). I've gradually moved to the dark side in several ways: I no longer care about hygiene[1] or making macros easy to compile[2]. But I still hold on to lexical scope for reasons I can't fully articulate. If unit tests are as great as I say they are, do we need lexical scope? Without them changes may break seemingly distant, unrelated code. Something to think about.
>> If unit tests are as great as I say they are, do we need lexical scope?
Very very interesting. Unit testing.. This is such an engineering concept. Why not built in the language with meta tags (I don't know if it's possible at all)?
>> Without them changes may break seemingly distant, unrelated code. Something to think about.
Let's try the fun of an extreme code expansion language without any compromise :)
Some of you were right, there is a sensible problem in names/scope I've not expected. But I've the answer to everything :)
Libraries.
What are libraries? There are application foundations. In other words, applications are built on top of libraries.
So let's make it as it should.
A libraries is a function which takes in arguments an other libraries or an end application.
Let loadlast be a function which bind to a symbol the eval of the last instruction of a file. And let use the arc evaluation syntax.
App.ext:
////////////// app.ext ////////////////////
(loadlast '"lib1.ext" 'MyLib1)
(loadlast '"lib2.ext" 'MyLib2)
(loadlast '"lib3.ext" 'MyLib3)
(= 'MyApp
'(*put your application here*))
(MyLib1 '(MyLib2 '(Mylib3 MyApp))) ; This launches the whole
MyApp ; that makes MyApp a lib. MyApp is working with MyLib1, MyLib2 and MyLib3 and thus must be embed at least on top of a stack which contains them.
Lib1.ext:
///////////// lib1.ext ////////////////////
{
*blabla*
{
arg1; it evaluates (MyLib2 '(Mylib3 MyApp)) which can now use lib1 via the dynamic scope system
}
*blabla*
}