Difference between revision 21 and current revision
No diff available.i found this little Hoon example a persuasive argument towards having some basic constructs have punctuation syntax (as an aside, it also persuades me that what makes Hoon hard to read is not just the use of 'line noise' instead of alphanumeric keywords for basic constructs, but rather, the use of non-descriptive words such as 'clam', 'vase', 'whip', 'kelp' for almost function names and arguments, variable name, and language concepts; and also the sheer NUMBER of punctuation digraphs):
++ add
|= [a=@ b=@]
^- @
?: =(0 a) b
$(a (dec a), b +(b))
attribute add {
function(left-operand: atom, right-operand: atom)
produce atom
if equals(0, left-operand) {
right-operand
} else {
recurse(left-operand (decrement left-operand)),
right-operand (increment right-operand))
}
}
-- https://news.ycombinator.com/item?id=8585178
so mb we should reconsider that in Oot and give eg. 'if' a short punctuation operator, and syntax (so that the grouping becomes implicit).
if we allow digraphs for these things, there are a lot of them.
now, in Hoon, i think you might have to memorize the number of arguments that various digraphs take, which i don't like. In Hoon, the first character of each digraph is a functional category. How about we arrange things so that the number of arguments of Oot digraphs can be deduced from their first character?
also, as i noted previously, we can allow custom infix operators using punctuation bound to previously-defined alphanumeric functions, and the precedence can be deduced from the first character of the operator.
---
samatman 871 days ago
| parent | on: Clojure for the Brave and True – Functional Progra... |
(serve (fry (add-pan kale (fry (add-pan (dice onions)))))
cynicalkane 871 days ago
Better is
(->> onions
dice add-pan fry (add-pan kale) fry serve))---
dont forget that we need a range constructor! if . and .. are taken then mb "..."? Mb that seems hard to remember.. mb if '#' is then infix # eg 1#10 = 1..10? nah, anyway i dont think # will be len, len is good enough
---
dont forget we need a % as in Python's '%' for string format (string interpolate). Since $ has to do with interpolation in Oot, mb use $$ for this? And we could use '$' for 'it'. No, we probably need to save $$ for some metaprogrammy 'substitute'. Not sure about '$' (mb 'it'? or mb the environtment, eg current variable bindings). Is $ available for custom binop and unary ops? Probably not b/c $alpha is still needed for "immediately interpolate variable with the name 'alpha'", ie the opposite of ?alpha.
---
if two modules try to export the same name, you can't just import them both (and let the second one implicitly shadow the first); instead you must use import..with..as (like in Python, but whatever syntax we have instead). But then what if a module tries to overwrite a builtin? options: (a) disallow overriding builtings; or (b) in this case you have to import..builtins..as explicitly, which removes the otherwise-implicit import of it in the beginning ; or (c) add a new construct, mb import..overwriting
---
i like Python's use of alphabetical 'and' and 'or', but our "Only punctuation affects the way things are parsed." rule forbids this, so we need to reserve some characters for it. I looked thru http://rosettacode.org/wiki/Logical_operations and it seems like most everyone uses either alpha 'and' and 'or' or they use && and
| or mb & and | . So how about we use & and | . This means we have to rethink using both | and | for different kinds of piping, but i think it's worth it. We can always use | and | instead for the piping. | |||||
---
is '%' is still in python 3 for 'format' (string interpolation)? Yes: http://stackoverflow.com/questions/14753844/python-3-using-s-and-format
---
OK, so operator precedence/order of operations:
We want to allow custom operators. But we don't want to allow custom precedence (unlike Haskell, which does allow this) because it means you cannot parse expressions without looking up the function definitions to find the custome precedences of any included custom operators.
One way around this is to have custom operators have a fixed precedence. Another way, the way we are choosing, is to let the punctuation for the operator determine the precedence.
Most languages have a bunch of precedence levels, but i don't want to:
There's no point to having operator precedence if people can't memorize it. The only point of operator precedence is to remove the need to clutter up code with parentheses, by making the parentheses implied. If people can't memorize the precedence table, then they have to look up the rules in order to understand code which relied on the unfamiliar parts of the precedence table; in which case it's better to force use of explicit parentheses for readability (to save readers the time of looking that up).
Are equations and <= comparisons tighter or looser than and/or? Python and golang disagree (and i couldn't remember which way Python did it anyways, which means this part of the precedence table is too much to remember). So we should leave these things at equal precedence.
Go has 5 levels of precedence, which is less than most languages, so start there. It goes: multiplication/shifts/bitwise-ANDs, then addition/bitwise-ORs, then comparisons, then &&, then
| . This puts && and | at different levels, which we don't want. And these are on different levels from <=, which we don't want. We have 'div' for division, not '/'; and we don't want to allow custom operators starting with '-' b/c for now we are saving that for 'mark'. It is not yet clear if we will give shifts and bitwise operators punctuation in core, so ignore them for now. And we also have a '%' operator, which is like Python's "in", and a '%%', which is like Python's "%" (format/string interpolation); Python puts 'in' with <=, and puts '%' with *; i guess we'll put % with <=. Making these changes, we get three levels: |
unary: ! eg ! or !-
binary:
eg arg1 * arg2 or arg1 *
| arg2 |
ternary: <..x..> where .. can be more punctuation (reflected left-to-right the second time) eg arg1 <arg2> arg3 or arg1 <-arg2-> arg3
So:
Custom operators must be all punctuation.
They must start with one of:
| (binary) |
In Oot the precedence is determined by the first (punctuation) character of the operator.
actually using
| and | for piping isnt as good b/c we wanted something easy to reverse the direction of a chain of functions, eg before we had: | |||
x
| g | f == f(g(x)) |
but x
| g | f is clumsy to type. |
could say "'
| ' means OR when freestanding, or reverse-compose when infix not freestanding" but that's confusing. |
so this is an open question.
it would be nice if '*' or '+' implied associativity but then we'd want non-associative prefix symbols for those precedence levels too, so that there is a way for non-associative operators to be in that precedence level, right? But i am running low on punctuation, so i guess we can't have that. So either the * and - precedence levels imply associativity, or associativity can only be specified via a type annotation.
---
if '-' is "not" we may have a problem bc '-1' is different from 0, but -T is F; so mb do use ! for not after all
---
is prefix - also a custom unary prefix?
so do need assoc and nonassoc custom operators?
---
does custom op prefix infixify alphanumeric name? I'm thinking yes (later: nah just '%'). in which case we don't need separate infixify. if not, what is precedence of infixified? Q: what is it in Haskell A: seems like it is whatever is custom defined for the alphanumeric function, or 9 (the highest) otherwise: [1]