Lambda Lambda Lambda

I'd come up with the temporary syntax of ~>[args]{function body} for lambdas but it was very not in line with the rest of the language, and not at all self-evident, and I just didn't like it.

Then i saw how python handles it:

# lambda arguments : expression
x = lambda a : a + 10
print(x(5))

So what if we built off of that? What if lambda: is a special function (basically a macro)?

# lambda: []
#		do_something:

var: plus_ten lambda: [a]
	return: +: a 10

println plus_ten: 5
#=> outputs 15

under the covers it'd be converted to

(def x (fn [a]
           (+ a 10)))
(print  (x 5) )

Janet's fine with printing a non-string value so we don't have to wrap it in a (string/format "%s" (x 5)) or anything like that.

Here's what it'd look like using it in a map.

map: a_list lambda: [x]
				return: +: x 11

map: a_list <lambda: [x]
				return: +: x 11>

map: a_list plus_ten

The first 2 convert to

(map (fn [x]
         (+ x 11)) a_list)

and the last is

(map plus_ten a_list)

We learn 2 things from the above.

  1. yup, looks legit. Not only that, looks like any other function call. YAAAY
  2. it's legal to indent as many levels as you want in a single line. in this case going from 1 to 3. We already knew it was legal to dedent multiple levels. Now I'm explicitly declaring that as acceptable.

And yes, I've decided to make maps function as map: list function instead of the lisp standard of (map function list) becasue the "normal" order always felt weird to me.

And that colon after return: is still bugging me. Also, I'm just not a fan of the explicit return in a lambda. In that context it feels excessively verbose. To me a lambda is all "hey i just need a quickie function in here that isn't going to be referenced anywhere else." You rarely write a lambda for side-effects. They tend to be written explicitly for their return value.

Return

I'm explicitly requiring return to be called in a function for two reasons:

  1. when functions have implicit returns it is frequently impossible to tell if the thing a function is returning is something you can rely on, or just the coincidental output of the last line of a function. That is to say, I don't know if i can trust that your function will always return a boolean as it is now, or if that was just an unintented side-effect of the last action you performed in you rfunction.
  2. it's sometimes non-obvious what a function is or could be returning, and you have to spend a couple minutes working your way through its branches to figure it out.

So, that's why I'm calling it out in lambdas. However, as I write this, I'm realizing that contracts would solve this problem.

There could be a compile-time check to see if a function has a contract, and if so, doesn't require a return, but any function without a contract, would require one. I'm not sure I like the inconsistent result then. Some functions would have a return and some wouldn't.

… Just fixed return so that it no longer needs a colon after it. I needed to move the RETURN token down below the FUNCTION_NAME token that referenced it.

Line continuation

I'm running into instances where it's just not clear what function the following line is an argument to. For example:

        if: and: x true
            y
            z

It would be legitimate to assume that y is a 3rd parameter to and:. It's on a new line, and it's indented more than the prior line. At the same time, it's also reasonable to assume that it's a 2nd argument to if: which Is what I intended it as.

The current solution to this would be to say

        if: <and: x true>
            y
            z

And that's fine, but the code is waving a metaphorical red flag at me and letting me know that we're going to need the ability to say "this thing continues on the next line." Python has it, and those folks know what they're doing with indentation.

Yes, I really should brush up on my Python here rather than re-inventing their wheel badly, but until then, I've decided that my continuation string will be ... or an actual elipsis (). Because an elipsis indicates that the sentence / line has literally trailed off without completing.

I'll figure out what the right rules around its usage are later. Correction, I'll shamelessly rip-off Python's rules for its usage later.

Python rules: "Line continuation is automatic when the split comes while a statement is inside parenthesis ( () ), brackets ( [] ) or braces ( {} )." - Rhino Developer

So, there's your answer. You need the line continuation indicator whenever the line is continuing but it's not in a grouping. That… doesn't actually work for me. I want this to be valid syntax:

        if: true
            do_this:
            do_that:

So, back to this

        if: and: x true
            y
            z

I think it's just too ambiguous. I can't describe a rule in english that clearly describes that such that y is unambiguously an argument to if: and not and:.

Also, I just realized that it's also not clear if x is an argument of if: or and:

So, that means we have to do this

        if:
            and:
                x true
            y
            z

Or

        if: <and: x true>
            y
            z