lmm 1 day ago [-]
I genuinely prefer
n = if expr trueVal else falseVal
(which is what e.g. Scala does) over meaningless-unless-memorized '?' and ':'
reply
---
i note that i informally use period for 'objectname.field1' alot. Also, i like/use 1:3 for the range operator a lot (1:3 == [1 2 3])
---
for x..y, i am still thinking it might be the way to reference the edge between x and y. However, the 'unix filepath' convention of the parent of x is also attractive. Could always use "x...y" for the edge; however following the unix convention, this would make more sense if it meant 'root'. So could always use "x....y" for the edge. So:
x.y: "start at node x and follow edge labeled y" x..y: "start at node x, follow the 'parent' edge, then follow edge labeled y" x...y: "start at node x, follow the 'root' edge, then follow edge labeled y" x....y: "start at node x, go to the reification of the edge labeled y"
since all nodes exist within some graph (i guess?), the 'root' edge always exists (i guess the 'root' node is the metanode for the graph?). However, the 'parent' edge is not always there, since only some graphs will be trees.
---
without looking back on my earlier thinking about it, for functions i am guessing:
we want MLish notation (juxtaposition, not parens, to apply functions)
BUT, what about 0-ary functions? By the juxtaposition rule, they are evaluated whenever mentioned, eg if 'f' is a 0ary function that evaluates to '4', and if 'g' is the addition functions, then "g (f) 3 == g (4) 3 == 7". Note that we didn't get a type error "can't add a function to an integer", because "f" was applied to the zero arguments to the right of it. So, we may need some notation to 'freeze' a fully-applied function, eg "`f" or somesuch. 'Freeze' can also be used on functions which were non-zeroary but now are zero-ary because they are fully applied: "`g 4 3" is a zero-ary function that returns 7, it is not the number 7. If everything were referentially transparent there would not be a difference, but with impure functions there is a difference.
And what about optional/default arguments? There are two obvious choices (you could do some other things, i guess, like don't set them until the runtime actually evaluates the function, but i guess that's more confusiong): either they are set to their defaults the first time any arguments are given to the function (as soon as possible), OR they are set to their defaults when the function is fully evaluated according to its definition (as late as possible). In either case, the 'freeze' operator prevents them from being set. Right now i think 'as late as possible' is the way to go, eg if "g" is "+" but with some default arguments, then partially applied "g 4" leaves the defaults open but "g 4 3" assign the defaults; "`g 4 3" does not assign the defaults, however.
---
Erlang vs. Java syntax:
" -module(geometry). -export([area/1]).
area({rectangle, Width, Ht}) -> Width * Ht; area({square, X}) -> X * X; area({circle, R}) -> 3.14159 * R * R.
Now we’ll compile and run it in the Erlang shell:
1> c(geometry). {ok,geometry} 2> geometry:area({rectangle, 10, 5}). 50 3> geometry:area({circle, 1.4}). 6.15752
Pretty easy… Here’s some Java that does something similar:
abstract class Shape { abstract double area(); }
class Circle extends Shape { final double radius; Circle(double radius) { this.radius = radius; } double area() { return Math.PI * radius*radius; } }
class Rectangle extends Shape { final double ht; final double width; Rectangle(double width, double height) { this.ht = height; this.width = width; } double area() { return width * ht; } }
class Square extends Shape { final double side; Square(double side) { this.side = side; } double area() { return side * side; } } " -- https://pragprog.com/articles/erlang/
---
so can we do similar, but with type declarations?
iface shape = {num = area(shape);} iface rectangle <: shape = {num width, height; area = {width*height}} iface square <: shape = {num length; area = {length*length}} iface circle <: shape = {num radius; area = 3.14159 * radius * radius}
of course,
---
y'know, the Lisp convention of ending predicate function names with '?' does aid readability. Eg:
(->> (range 5 10) ;; (5 6 7 8 9) List (filter odd?) ;; (5 7 9) (map inc) ;; (6 8 10) (reduce +)) ;; 24 " -- from [1]
---
in clojure, having the keys in a dict literal just be symbols prefixed with ':' leads to some uniformity:
" Nested updates is also easy to do. Works for both maps and vectors.
(assoc-in {:a {:b {:c 1}}} [:a :b :c] 2) ;; ^__target ^__path ^__value
(update-in {:a {:b {:c 1}}} [:a :b :c] inc) ;; ^__target ^__path ^__updating function
note the uniformity between the target and the path here (between {:a {:b {:c 1}}} and [:a :b :c]). If dicts were like {a={b={c=1}}}, then the path wouldn't look the same.
what exactly is the ':' doing there? Is it just like a 'quote' in Lisp? Probably not quite; it's also probably alerting the language that this is a variable. I think keywords are translated to unique opaque integer by the language implementation. So
but otoh it's nice to have a non-shifted key like '=' instead of shifted ':' for such a common occurrence.
so mb we should do
(assoc-in {a= {b= {c= 1}}} [a= b= c=] 2) ;; ^__target ^__path ^__value
?
---
---
'keywords' (like :a, i think) vs 'symbols' in clojure: http://stackoverflow.com/questions/1527548/why-does-clojure-have-keywords-in-addition-to-symbols
---
" FizzBuzz?. Here is an example in Java:
public class FizzBuzz?