cliffclick / aa

Cliff Click Language Hacking
Apache License 2.0
276 stars 22 forks source link

Named arguments #8

Open cliffclick opened 3 years ago

cliffclick commented 3 years ago

From Aaron: call with a struct instead of a tuple: (fun @{x=123,y=456}). Needs default args also.

AaronGoldman commented 3 years ago

Python uses a = for optional argument and requires the non-default arguments at the end.

>>> f = lambda a=1, b: a+b
SyntaxError: non-default argument follows default argument

this is because they allow mixed calling f(1, b=2) so positional arguments lose meaning after a left out optional if an aa call is either a call by struct or a call by tuple this restriction may not be warented

f = {a, b=2, c=3 -> a + b + c}

f @{a=1}           \\ 6
f @{a=1, b=4}      \\ 8
f @{a=1, c=5}      \\ 8
f @{a=1, b=4, c=5} \\ 10
f @{}              \\ type error @{} !< @{a}
cliffclick commented 3 years ago

Looks good to me!

cliffclick commented 3 years ago

Usual question: what is the scope of the default expressions:

a=some_expensive_default;
g=2;
f = {a, b=g/*uses 'g=2' by default*/, c=a/*uses prior a and NOT argument a*/ -> a + b + c}

The expressions for 'a' and 'g' are not available at the call-site, so probably end up in a curried version of 'f' used by the default call sites.

Ahh... which leads me to the cost model: Default arguments are pre-computed at the function definition point, just in case a curried /default version is called. This cost can be further delayed until first-use by defining the default argument as a Future. 'aa' will not auto-Future default arguments without some sort of syntactic-sugar request.

AaronGoldman commented 3 years ago

I feel like this is just a special case of the scope within expressions. Whether it is a tuple, a struct, or a args what do we want the comma to mean?

If comma means strict sequential ordering

n = 0;
f = { -> n=n+1; n}

(f(),f(),f()) \\ (1, 2, 3)
@{a=f(), b=a, c=f()} \\ @{a=4, b=4, c=5}

or aa could not have the ordering

(f(),f(),f()) \\ non determanistic 1,2,3 in any order
@{a=f(), b=a, c=f()} \\ Error: a used before definition

The win of the first one is that I can build up a namespace

@{
  func_a = { -> ...},
  func_b = { -> ...},
  func_c = { -> func_a() + func_b },
}

if the normal import is to eval the file and have the last form returned we can have a clean literal over

func_a = { -> ...}
func_b = { -> ...}
func_c = { -> func_a() + func_b }

@{func_a=func_a, func_b=func_b, func_c=func_c}

which is a clean way to do exports but not as clean as the ordered one.

cliffclick commented 3 years ago

'aa' as a whole is strictly deterministic, with parallelism coming some other (TBD) constructions.
Reasoning: easier to understand the meaning of code. Commas separate arguments in a tuple (and otherwise have nothing to do with ordering). Struct definitions definitely have order, and can be used to build up a namespace - and they use semi-colon not comma. Reasoning: Most languages use semi-colon to end field definitions so lower weirdness budget to go with the crowd; and also this is the same grammar (and same parser) as the normal expression parsing, so again less mental budget to understand the code.