Is this actually the way the first expression is being expanded? I can think of situations where I would want (foo:bar.arg) to be expanded to (foo (bar arg)) not (foo ((bar arg))). Just a thought.
The plan with intrasymbol syntax is (a) not to break traditional Lisp read and (b) to expand in place. If you have those two constraints, instead of just saying "ok, put any syntax anywhere," you can introduce syntax into Lisp without getting too unLispy.
Right. Maybe it's the traditional Lisp read that's the main factor here because it seems that you could expand in place without issue given even arbitrary expressions.
If a.b expands to (a b) then (f v w).(g x y) would just expand to ((f x y) (g x y)). At first glance, that definitely appears to be a cool way to grab just one of the results from a function return (ala (f x y).2).
Hmm, on the down side, you could have statements like (or worse):
(bst-find tree 45 f<).(if (< 10 42) (/ 4 3)
(> 4 2) x
'r)
That being said, having to change read to get this to work may affect far too much and make arc too ugly.
I think the ! concept you outline has some appeal because it requires us to treat state change as a specific entity- Maybe then it would be possible to have a way to turn it on or off for a chunk of code in order to have enforced purely functional code (sorta like in Haskell, but at runtime)
I could envision something like:
(= x '(2 5 3 4 1))
(def foo ()
(sort! < x))
(w/out-mutation
(foo))
***ERROR- FORBIDDEN EXTERNAL MUTATION IN FUNCTION (FOO)***
Of course, there would have to be an ability by the compiler to automatically substitute code using this construct to do something more efficient when mutation is permitted.
In order to benefit most from this, languages such as haskell that include this feature have their core library functions written such that the most useful parameters to be "curried away" (which are usually obvious) are located at the end of the list.
For instance, you may want to redefine the function signature for subseq from:
(def subseq (seq start (o end (len seq)))
...)
to:
(def subseq ((start (o end (len seq))) seq)
...)
With that signature you would write (subseq '(1 4) "qwerty") which is arguably a more elegant style, as well. (yes, you can actually place an optional param inside of a destructuring like this in arc so it isn't at the end) Of course, the need for the quote is perhaps a small minus for some people.
Then you could use it in a curried fashion in a useful way:
;chop two letters off of each word
> (map (subseq '(2)) '("apple" "orange" "banana")))
("ple" "ange" "nana")
However, the core arc library commands, by their nature, are very general and hence have few mandatory parameters. However, most functions for any actual application will be far more specific and hence, I believe, will tend to be loaded with mandatory parameters. This is the use for case which function currying would be very valuable.
According to your essays, a major paradigm of arc is to let hackers do as much as possible, without giving errors when the compiler is worried things are "too dangerous". Partial application/function currying is my #1 request for arc right now... I would love it if any arc function given too few non-optional parameters would perform an implicit curry.
Incidentally, [...] syntax helps amortize the problem of non-existent curry: curried (map fn) == [map fn _]
Adding curry support will also require us to define flipped parameters, i.e.
(def flip (f x y)
(f y x))
Or better:
(mac flip ( (f x . ys) )
(if
(no ys)
(w/uniq p
`(fn (,p) (,f ,p ,x)))
(is 1 (len ys))
`(,f ,(car ys) ,x)
(ero "flip: more than two parameters in call")))
Yeah, the colon operator has many limitations, I've noticed... I haven't been able to get it to work for any case that doesn't involve simple symbol names for functions...
you are correct about the parens on prn:x... I thought I had a clever trick from making them unecessary, but it didn't pan out when I sat down to work out the necessary transformations... creating decent language primitives is hard...
...your "line noise" comment also is a good point...
This stuff is hard. I looked into implementing general splicing functionality but it is not trivial. Reading @bar and translating it to (splice 'bar) is easy enough, but then you would have to examine the arguments of every sexp before evaluating it to handle the splice. I guess it's not particularly difficult but it would likely be a performance hit. Perhaps there is a clever trick to do general splicing.
I think an arc execution model should have support for finegrained control over timeout and cpu load... I would love it if I could build a website in a language (such as arc) that would allow me to easily run user-supplied code with enough control in the language where I can say "your code must complete in 0.1 sec or 1000 cpu slices or it will be stopped"